+ /* set the descriptor of the new value */
+ _desc(result).exponent_size = exp_size;
+ _desc(result).mantissa_size = mant_size;
+ _desc(result).clss = _desc(value).clss;
+
+ _sign(result) = _sign(value);
+
+ /* when the mantissa sizes differ normalizing has to shift to align it.
+ * this would change the exponent, which is unwanted. So calculate this
+ * offset and add it */
+ val_bias = (1<<_desc(value).exponent_size)/2-1;
+ res_bias = (1<<exp_size)/2-1;
+
+ exp_offset = (res_bias - val_bias) - (_desc(value).mantissa_size - mant_size);
+ sc_val_from_long(exp_offset, temp);
+ sc_add(_exp(value), temp, _exp(result));
+
+ /* _normalize expects normalized radix point */
+ if (_desc(val).clss == SUBNORMAL) {
+ sc_val_from_ulong(1, NULL);
+ _shift_left(_mant(val), sc_get_buffer(), _mant(result));
+ } else if (value != result) {
+ memcpy(_mant(result), _mant(value), value_size);
+ } else {
+ memmove(_mant(result), _mant(value), value_size);
+ }
+
+ _normalize(result, result, 0);
+ TRACEPRINTF(("Cast results in %s\n", fc_print(result, temp, value_size, FC_PACKED)));
+ return result;
+}
+
+char* fc_get_max(unsigned int exponent_size, unsigned int mantissa_size, char* result)
+{
+ if (result == NULL) result = calc_buffer;
+
+ _desc(result).exponent_size = exponent_size;
+ _desc(result).mantissa_size = mantissa_size;
+ _desc(result).clss = NORMAL;
+
+ _sign(result) = 0;
+
+ sc_val_from_ulong((1<<exponent_size) - 2, _exp(result));
+
+ sc_max_from_bits(mantissa_size + 1, 0, _mant(result));
+ sc_val_from_ulong(2, NULL);
+ _shift_left(_mant(result), sc_get_buffer(), _mant(result));
+
+ return result;
+}
+
+char* fc_get_min(unsigned int exponent_size, unsigned int mantissa_size, char *result)
+{
+ if (result == NULL) result = calc_buffer;
+
+ fc_get_max(exponent_size, mantissa_size, result);
+ _sign(result) = 1;
+
+ return result;
+}
+
+char* fc_get_snan(unsigned int exponent_size, unsigned int mantissa_size, char *result)
+{
+ if (result == NULL) result = calc_buffer;
+
+ _desc(result).exponent_size = exponent_size;
+ _desc(result).mantissa_size = mantissa_size;
+ _desc(result).clss = NAN;
+
+ _sign(result) = 0;
+
+ sc_val_from_ulong((1<<exponent_size)-1, _exp(result));
+
+ /* signaling NaN has non-zero mantissa with msb not set */
+ sc_val_from_ulong(1, _mant(result));
+
+ return result;
+}
+
+char* fc_get_qnan(unsigned int exponent_size, unsigned int mantissa_size, char *result)
+{
+ if (result == NULL) result = calc_buffer;
+
+ _desc(result).exponent_size = exponent_size;
+ _desc(result).mantissa_size = mantissa_size;
+ _desc(result).clss = NAN;
+
+ _sign(result) = 0;
+
+ sc_val_from_ulong((1<<exponent_size)-1, _exp(result));
+
+ /* quiet NaN has the msb of the mantissa set, so shift one there */
+ sc_val_from_ulong(1, _mant(result));
+ /* mantissa_size >+< 1 because of two extra rounding bits */
+ sc_val_from_ulong(mantissa_size + 1, NULL);
+ _shift_left(_mant(result), sc_get_buffer(), _mant(result));
+
+ return result;
+}
+
+char* fc_get_plusinf(unsigned int exponent_size, unsigned int mantissa_size, char *result)
+{
+ if (result == NULL) result = calc_buffer;
+
+ _desc(result).exponent_size = exponent_size;
+ _desc(result).mantissa_size = mantissa_size;
+ _desc(result).clss = NORMAL;
+
+ _sign(result) = 0;
+
+ sc_val_from_ulong((1<<exponent_size)-1, _exp(result));
+
+ sc_val_from_ulong(0, _mant(result));
+
+ return result;
+}
+
+char* fc_get_minusinf(unsigned int exponent_size, unsigned int mantissa_size, char *result)
+{
+ if (result == NULL) result = calc_buffer;
+
+ fc_get_plusinf(exponent_size, mantissa_size, result);
+ _sign(result) = 1;
+
+ return result;
+}
+
+int fc_comp(const void *a, const void *b)
+{
+ const char *val_a = (const char*)a;
+ const char *val_b = (const char*)b;
+ int mul = 1;
+
+ /*
+ * shortcut: if both values are identical, they are either
+ * Unordered if NaN or equal
+ */
+ if (a == b)
+ return _desc(val_a).clss == NAN ? 2 : 0;
+
+ /* unordered if one is a NaN */
+ if (_desc(val_a).clss == NAN || _desc(val_b).clss == NAN)
+ return 2;
+
+ /* zero is equal independent of sign */
+ if ((_desc(val_a).clss == ZERO) && (_desc(val_b).clss == ZERO))
+ return 0;
+
+ /* different signs make compare easy */
+ if (_sign(val_a) != _sign(val_b))
+ return (_sign(val_a)==0)?(1):(-1);
+
+ mul = _sign(a) ? -1 : 1;
+
+ /* both infinity means equality */
+ if ((_desc(val_a).clss == INF) && (_desc(val_b).clss == INF))
+ return 0;
+
+ /* infinity is bigger than the rest */
+ if (_desc(val_a).clss == INF)
+ return 1 * mul;
+ if (_desc(val_b).clss == INF)
+ return -1 * mul;
+
+ /* check first exponent, that mantissa if equal */
+ switch (sc_comp(_exp(val_a), _exp(val_b))) {
+ case -1:
+ return -1 * mul;
+ case 1:
+ return 1 * mul;
+ case 0:
+ return sc_comp(_mant(val_a), _mant(val_b)) * mul;
+ default:
+ return 2;
+ }
+}
+
+int fc_is_zero(const void *a)
+{
+ return _desc(a).clss == ZERO;
+}
+
+int fc_is_negative(const void *a)
+{
+ return _sign(a);
+}
+
+int fc_is_inf(const void *a)
+{
+ return _desc(a).clss == INF;
+}
+
+int fc_is_nan(const void *a)
+{
+ return _desc(a).clss == NAN;
+}
+
+int fc_is_subnormal(const void *a)
+{
+ return _desc(a).clss == SUBNORMAL;
+}
+
+char *fc_print(const void *a, char *buf, int buflen, unsigned base)
+{
+ const char *val;
+ char *mul_1;
+
+ val = (const char*)a;
+
+ mul_1 = alloca(calc_buffer_size);
+
+ switch (base) {
+ case FC_DEC:
+ switch (_desc(val).clss) {
+ case INF:
+ if (buflen >= 8+_sign(val)) sprintf(buf, "%sINFINITY", _sign(val)?"-":"");
+ else snprintf(buf, buflen, "%sINF", _sign(val)?"-":NULL);
+ break;
+ case NAN:
+ snprintf(buf, buflen, "NAN");
+ break;
+ case ZERO:
+ snprintf(buf, buflen, "0.0");
+ break;
+ default:
+ /* XXX to be implemented */
+#ifdef HAVE_LONG_DOUBLE
+ /* XXX 30 is arbitrary */
+ snprintf(buf, buflen, "%.30LE", fc_val_to_float(val));
+#else
+ snprintf(buf, buflen, "%.18E", fc_val_to_float(val));
+#endif
+ }
+ break;
+
+ case FC_HEX:
+ switch (_desc(val).clss) {
+ case INF:
+ if (buflen >= 8+_sign(val)) sprintf(buf, "%sINFINITY", _sign(val)?"-":"");
+ else snprintf(buf, buflen, "%sINF", _sign(val)?"-":NULL);
+ break;
+ case NAN:
+ snprintf(buf, buflen, "NAN");
+ break;
+ case ZERO:
+ snprintf(buf, buflen, "0.0");
+ break;
+ default:
+#ifdef HAVE_LONG_DOUBLE
+ snprintf(buf, buflen, "%LA", fc_val_to_float(val));
+#else
+ snprintf(buf, buflen, "%A", fc_val_to_float(val));
+#endif
+ }
+ break;
+
+ case FC_PACKED:
+ default:
+ snprintf(buf, buflen, "%s", sc_print(_pack(val, mul_1), value_size*4, SC_HEX));
+ break;
+ }