File: mlgsl_ieee.c

package info (click to toggle)
ocamlgsl 0.3.5-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 3,444 kB
  • ctags: 2,901
  • sloc: ml: 7,956; ansic: 6,796; makefile: 303; sh: 87; awk: 13
file content (145 lines) | stat: -rw-r--r-- 2,935 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* ocamlgsl - OCaml interface to GSL                        */
/* Copyright () 2002 - Olivier Andrieu                     */
/* distributed under the terms of the GPL version 2         */


#include <gsl/gsl_ieee_utils.h>

#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <caml/memory.h>

#include "wrappers.h"

static value rep_val(const gsl_ieee_double_rep *r)
{
  CAMLparam0();
  CAMLlocal2(v, m);
  m=copy_string(r->mantissa);
  v=alloc_small(4, 0);
  Field(v, 0)= Val_int(r->sign);
  Field(v, 1)= m;
  Field(v, 2)= Val_int(r->exponent);
  Field(v, 3)= Val_int(r->type - 1);
  CAMLreturn(v);
}

value ml_gsl_ieee_double_to_rep(value x)
{
  double d;
  gsl_ieee_double_rep r;
  d = Double_val(x);
  gsl_ieee_double_to_rep(&d, &r);
  return rep_val(&r);
}

value ml_gsl_ieee_env_setup(value unit)
{
  gsl_ieee_env_setup();
  return Val_unit;
}

value ml_gsl_ieee_set_mode(value oprecision, value orounding, value ex_list)
{
  const int precision_conv [] = { 
    GSL_IEEE_SINGLE_PRECISION, GSL_IEEE_DOUBLE_PRECISION, GSL_IEEE_EXTENDED_PRECISION };
  const int round_conv [] = { 
    GSL_IEEE_ROUND_TO_NEAREST, GSL_IEEE_ROUND_DOWN, GSL_IEEE_ROUND_UP, GSL_IEEE_ROUND_TO_ZERO };
  int mask_conv [] = {
    GSL_IEEE_MASK_INVALID, GSL_IEEE_MASK_DENORMALIZED,
    GSL_IEEE_MASK_DENORMALIZED, GSL_IEEE_MASK_OVERFLOW,
    GSL_IEEE_MASK_UNDERFLOW, GSL_IEEE_MASK_ALL,
    GSL_IEEE_TRAP_INEXACT } ;
  int mask = convert_flag_list(ex_list, mask_conv);

#define Lookup_precision(v) precision_conv[ Int_val(v) ]
#define Lookup_round(v)     round_conv[ Int_val(v) ]

  gsl_ieee_set_mode(Opt_arg(oprecision, Lookup_precision, 0), 
		    Opt_arg(orounding,  Lookup_round, 0), 
		    mask);
  return Val_unit;
}

#ifdef HAVE_FENV
#include <fenv.h>

static int except_conv [] = {
#ifdef FE_INEXACT
    FE_INEXACT,
#else
    0,
#endif
#ifdef FE_DIVBYZERO
    FE_DIVBYZERO,
#else
    0,
#endif
#ifdef FE_UNDERFLOW
    FE_UNDERFLOW,
#else
    0,
#endif
#ifdef FE_OVERFLOW
    FE_OVERFLOW,
#else
    0,
#endif
#ifdef FE_INVALID
    FE_INVALID,
#else
    0,
#endif
#ifdef FE_ALL_EXCEPT
    FE_ALL_EXCEPT,
#else
    0,
#endif
};

static int conv_excepts(value e)
{
  return convert_flag_list(e, except_conv);
}

static value rev_conv_excepts(int e)
{
  CAMLparam0();
  CAMLlocal2(v, c);
  int i, tab_size = (sizeof except_conv / sizeof (int)) ;
  v = Val_emptylist;
  
  for(i = tab_size-2; i >= 0 ; i--)
    if(except_conv[i] & e) {
      c = alloc_small(2, Tag_cons);
      Field(c, 0) = Val_int(i);
      Field(c, 1) = v;
      v = c;
    }
  CAMLreturn(v);
}

CAMLprim value ml_feclearexcept(value e)
{
  feclearexcept(conv_excepts(e));
  return Val_unit;
}

CAMLprim value ml_fetestexcept(value e)
{
  return rev_conv_excepts(fetestexcept(conv_excepts(e)));
}

#else /* HAVE_FENV */

CAMLprim value ml_feclearexcept(value e)
{
  return Val_unit;
}

CAMLprim value ml_fetestexcept(value e)
{
  return Val_emptylist;
}

#endif /* HAVE_FENV */