1 /***********************************************************************/
5 /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
7 /* Copyright 1996 Institut National de Recherche en Informatique et */
8 /* en Automatique. All rights reserved. This file is distributed */
9 /* under the terms of the GNU Library General Public License, with */
10 /* the special exception on linking described in file ../LICENSE. */
12 /***********************************************************************/
14 /* $Id: floats.c 8976 2008-08-02 11:02:28Z xleroy $ */
16 /* The interface of this file is in "mlvalues.h" and "alloc.h" */
31 #ifdef ARCH_ALIGN_DOUBLE
33 CAMLexport double caml_Double_val(value val)
35 union { value v[2]; double d; } buffer;
37 Assert(sizeof(double) == 2 * sizeof(value));
38 buffer.v[0] = Field(val, 0);
39 buffer.v[1] = Field(val, 1);
43 CAMLexport void caml_Store_double_val(value val, double dbl)
45 union { value v[2]; double d; } buffer;
47 Assert(sizeof(double) == 2 * sizeof(value));
49 Field(val, 0) = buffer.v[0];
50 Field(val, 1) = buffer.v[1];
55 CAMLexport value caml_copy_double(double d)
60 #define Restore_after_gc
61 Alloc_small(res, Double_wosize, Double_tag);
63 #undef Restore_after_gc
64 Store_double_val(res, d);
68 CAMLprim value caml_format_float(value fmt, value arg)
70 #define MAX_DIGITS 350
71 /* Max number of decimal digits in a "natural" (not artificially padded)
72 representation of a float. Can be quite big for %f format.
73 Max exponent for IEEE format is 308 decimal digits.
74 Rounded up for good measure. */
75 char format_buffer[MAX_DIGITS + 20];
82 for (p = String_val(fmt); *p != 0; p++) {
83 if (*p >= '0' && *p <= '9') {
84 i = atoi(p) + MAX_DIGITS;
85 if (i > prec) prec = i;
89 for( ; *p != 0; p++) {
91 i = atoi(p+1) + MAX_DIGITS;
92 if (i > prec) prec = i;
96 if (prec < sizeof(format_buffer)) {
99 dest = caml_stat_alloc(prec);
101 sprintf(dest, String_val(fmt), Double_val(arg));
102 res = caml_copy_string(dest);
103 if (dest != format_buffer) {
104 caml_stat_free(dest);
109 /*CAMLprim*/ value caml_float_of_substring(value vs, value idx, value l)
111 char parse_buffer[64];
112 char * buf, * src, * dst, * end;
115 intnat flen = Long_val(l);
116 intnat fidx = Long_val(idx);
118 lenvs = caml_string_length(vs);
120 fidx >= 0 && fidx < lenvs && flen > 0 && flen <= lenvs - fidx
122 buf = len < sizeof(parse_buffer) ? parse_buffer : caml_stat_alloc(len + 1);
123 src = String_val(vs) + fidx;
127 if (c != '_') *dst++ = c;
130 if (dst == buf) goto error;
131 d = strtod((const char *) buf, &end);
132 if (end != dst) goto error;
133 if (buf != parse_buffer) caml_stat_free(buf);
134 return caml_copy_double(d);
136 if (buf != parse_buffer) caml_stat_free(buf);
137 caml_failwith("float_of_string");
140 CAMLprim value caml_float_of_string(value vs)
142 char parse_buffer[64];
143 char * buf, * src, * dst, * end;
147 len = caml_string_length(vs);
148 buf = len < sizeof(parse_buffer) ? parse_buffer : caml_stat_alloc(len + 1);
149 src = String_val(vs);
153 if (c != '_') *dst++ = c;
156 if (dst == buf) goto error;
157 d = strtod((const char *) buf, &end);
158 if (end != dst) goto error;
159 if (buf != parse_buffer) caml_stat_free(buf);
160 return caml_copy_double(d);
162 if (buf != parse_buffer) caml_stat_free(buf);
163 caml_failwith("float_of_string");
166 CAMLprim value caml_int_of_float(value f)
168 return Val_long((intnat) Double_val(f));
171 CAMLprim value caml_float_of_int(value n)
173 return caml_copy_double((double) Long_val(n));
176 CAMLprim value caml_neg_float(value f)
178 return caml_copy_double(- Double_val(f));
181 CAMLprim value caml_abs_float(value f)
183 return caml_copy_double(fabs(Double_val(f)));
186 CAMLprim value caml_add_float(value f, value g)
188 return caml_copy_double(Double_val(f) + Double_val(g));
191 CAMLprim value caml_sub_float(value f, value g)
193 return caml_copy_double(Double_val(f) - Double_val(g));
196 CAMLprim value caml_mul_float(value f, value g)
198 return caml_copy_double(Double_val(f) * Double_val(g));
201 CAMLprim value caml_div_float(value f, value g)
203 return caml_copy_double(Double_val(f) / Double_val(g));
206 CAMLprim value caml_exp_float(value f)
208 return caml_copy_double(exp(Double_val(f)));
211 CAMLprim value caml_floor_float(value f)
213 return caml_copy_double(floor(Double_val(f)));
216 CAMLprim value caml_fmod_float(value f1, value f2)
218 return caml_copy_double(fmod(Double_val(f1), Double_val(f2)));
221 CAMLprim value caml_frexp_float(value f)
224 CAMLlocal2 (res, mantissa);
227 mantissa = caml_copy_double(frexp (Double_val(f), &exponent));
228 res = caml_alloc_tuple(2);
229 Field(res, 0) = mantissa;
230 Field(res, 1) = Val_int(exponent);
234 CAMLprim value caml_ldexp_float(value f, value i)
236 return caml_copy_double(ldexp(Double_val(f), Int_val(i)));
239 CAMLprim value caml_log_float(value f)
241 return caml_copy_double(log(Double_val(f)));
244 CAMLprim value caml_log10_float(value f)
246 return caml_copy_double(log10(Double_val(f)));
249 CAMLprim value caml_modf_float(value f)
252 _float_eval frem; /* Problem with Apple's <math.h> */
257 CAMLlocal3 (res, quo, rem);
259 quo = caml_copy_double(modf (Double_val(f), &frem));
260 rem = caml_copy_double(frem);
261 res = caml_alloc_tuple(2);
267 CAMLprim value caml_sqrt_float(value f)
269 return caml_copy_double(sqrt(Double_val(f)));
272 CAMLprim value caml_power_float(value f, value g)
274 return caml_copy_double(pow(Double_val(f), Double_val(g)));
277 CAMLprim value caml_sin_float(value f)
279 return caml_copy_double(sin(Double_val(f)));
282 CAMLprim value caml_sinh_float(value f)
284 return caml_copy_double(sinh(Double_val(f)));
287 CAMLprim value caml_cos_float(value f)
289 return caml_copy_double(cos(Double_val(f)));
292 CAMLprim value caml_cosh_float(value f)
294 return caml_copy_double(cosh(Double_val(f)));
297 CAMLprim value caml_tan_float(value f)
299 return caml_copy_double(tan(Double_val(f)));
302 CAMLprim value caml_tanh_float(value f)
304 return caml_copy_double(tanh(Double_val(f)));
307 CAMLprim value caml_asin_float(value f)
309 return caml_copy_double(asin(Double_val(f)));
312 CAMLprim value caml_acos_float(value f)
314 return caml_copy_double(acos(Double_val(f)));
317 CAMLprim value caml_atan_float(value f)
319 return caml_copy_double(atan(Double_val(f)));
322 CAMLprim value caml_atan2_float(value f, value g)
324 return caml_copy_double(atan2(Double_val(f), Double_val(g)));
327 CAMLprim value caml_ceil_float(value f)
329 return caml_copy_double(ceil(Double_val(f)));
332 CAMLprim value caml_eq_float(value f, value g)
334 return Val_bool(Double_val(f) == Double_val(g));
337 CAMLprim value caml_neq_float(value f, value g)
339 return Val_bool(Double_val(f) != Double_val(g));
342 CAMLprim value caml_le_float(value f, value g)
344 return Val_bool(Double_val(f) <= Double_val(g));
347 CAMLprim value caml_lt_float(value f, value g)
349 return Val_bool(Double_val(f) < Double_val(g));
352 CAMLprim value caml_ge_float(value f, value g)
354 return Val_bool(Double_val(f) >= Double_val(g));
357 CAMLprim value caml_gt_float(value f, value g)
359 return Val_bool(Double_val(f) > Double_val(g));
362 CAMLprim value caml_float_compare(value vf, value vg)
364 double f = Double_val(vf);
365 double g = Double_val(vg);
366 if (f == g) return Val_int(0);
367 if (f < g) return Val_int(-1);
368 if (f > g) return Val_int(1);
369 /* One or both of f and g is NaN. Order according to the
370 convention NaN = NaN and NaN < x for all other floats x. */
371 if (f == f) return Val_int(1); /* f is not NaN, g is NaN */
372 if (g == g) return Val_int(-1); /* g is not NaN, f is NaN */
373 return Val_int(0); /* both f and g are NaN */
376 enum { FP_normal, FP_subnormal, FP_zero, FP_infinite, FP_nan };
378 CAMLprim value caml_classify_float(value vd)
380 /* Cygwin 1.3 has problems with fpclassify (PR#1293), so don't use it */
381 #if defined(fpclassify) && !defined(__CYGWIN32__) && !defined(__MINGW32__)
382 switch (fpclassify(Double_val(vd))) {
384 return Val_int(FP_nan);
386 return Val_int(FP_infinite);
388 return Val_int(FP_zero);
390 return Val_int(FP_subnormal);
391 default: /* case FP_NORMAL */
392 return Val_int(FP_normal);
397 #if defined(ARCH_BIG_ENDIAN) || (defined(__arm__) && !defined(__ARM_EABI__))
398 struct { uint32 h; uint32 l; } i;
400 struct { uint32 l; uint32 h; } i;
405 u.d = Double_val(vd);
406 h = u.i.h; l = u.i.l;
407 l = l | (h & 0xFFFFF);
410 return Val_int(FP_zero);
412 return Val_int(FP_subnormal);
413 if (h == 0x7FF00000) {
415 return Val_int(FP_infinite);
417 return Val_int(FP_nan);
419 return Val_int(FP_normal);
423 /* The [caml_init_ieee_float] function should initialize floating-point hardware
424 so that it behaves as much as possible like the IEEE standard.
425 In particular, return special numbers like Infinity and NaN instead
426 of signalling exceptions. Currently, everyone is in IEEE mode
427 at program startup, except FreeBSD prior to 4.0R. */
430 #include <osreldate.h>
431 #if (__FreeBSD_version < 400017)
432 #include <floatingpoint.h>
436 void caml_init_ieee_floats(void)
438 #if defined(__FreeBSD__) && (__FreeBSD_version < 400017)