Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
[fw/altos] / src / scheme / ao_scheme_float.c
1 /*
2  * Copyright © 2017 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include "ao_scheme.h"
16 #include <math.h>
17
18 static void float_mark(void *addr)
19 {
20         (void) addr;
21 }
22
23 static int float_size(void *addr)
24 {
25         if (!addr)
26                 return 0;
27         return sizeof (struct ao_scheme_float);
28 }
29
30 static void float_move(void *addr)
31 {
32         (void) addr;
33 }
34
35 const struct ao_scheme_type ao_scheme_float_type = {
36         .mark = float_mark,
37         .size = float_size,
38         .move = float_move,
39         .name = "float",
40 };
41
42 void
43 ao_scheme_float_write(ao_poly p)
44 {
45         struct ao_scheme_float *f = ao_scheme_poly_float(p);
46         float   v = f->value;
47
48         if (isnanf(v))
49                 printf("+nan.0");
50         else if (isinff(v)) {
51                 if (v < 0)
52                         printf("-");
53                 else
54                         printf("+");
55                 printf("inf.0");
56         } else
57                 printf ("%g", f->value);
58 }
59
60 float
61 ao_scheme_poly_number(ao_poly p)
62 {
63         switch (ao_scheme_poly_base_type(p)) {
64         case AO_SCHEME_INT:
65                 return ao_scheme_poly_int(p);
66         case AO_SCHEME_OTHER:
67                 switch (ao_scheme_other_type(ao_scheme_poly_other(p))) {
68                 case AO_SCHEME_BIGINT:
69                         return ao_scheme_bigint_int(ao_scheme_poly_bigint(p)->value);
70                 case AO_SCHEME_FLOAT:
71                         return ao_scheme_poly_float(p)->value;
72                 }
73         }
74         return NAN;
75 }
76
77 ao_poly
78 ao_scheme_float_get(float value)
79 {
80         struct ao_scheme_float  *f;
81
82         f = ao_scheme_alloc(sizeof (struct ao_scheme_float));
83         f->type = AO_SCHEME_FLOAT;
84         f->value = value;
85         return ao_scheme_float_poly(f);
86 }
87
88 ao_poly
89 ao_scheme_do_inexactp(struct ao_scheme_cons *cons)
90 {
91         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
92                 return AO_SCHEME_NIL;
93         if (ao_scheme_poly_type(ao_scheme_arg(cons, 0)) == AO_SCHEME_FLOAT)
94                 return _ao_scheme_bool_true;
95         return _ao_scheme_bool_false;
96 }
97
98 ao_poly
99 ao_scheme_do_finitep(struct ao_scheme_cons *cons)
100 {
101         ao_poly value;
102         float   f;
103
104         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
105                 return AO_SCHEME_NIL;
106         value = ao_scheme_arg(cons, 0);
107         switch (ao_scheme_poly_type(value)) {
108         case AO_SCHEME_INT:
109         case AO_SCHEME_BIGINT:
110                 return _ao_scheme_bool_true;
111         case AO_SCHEME_FLOAT:
112                 f = ao_scheme_poly_float(value)->value;
113                 if (!isnan(f) && !isinf(f))
114                         return _ao_scheme_bool_true;
115         }
116         return _ao_scheme_bool_false;
117 }
118
119 ao_poly
120 ao_scheme_do_infinitep(struct ao_scheme_cons *cons)
121 {
122         ao_poly value;
123         float   f;
124
125         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
126                 return AO_SCHEME_NIL;
127         value = ao_scheme_arg(cons, 0);
128         switch (ao_scheme_poly_type(value)) {
129         case AO_SCHEME_FLOAT:
130                 f = ao_scheme_poly_float(value)->value;
131                 if (isinf(f))
132                         return _ao_scheme_bool_true;
133         }
134         return _ao_scheme_bool_false;
135 }
136
137 ao_poly
138 ao_scheme_do_sqrt(struct ao_scheme_cons *cons)
139 {
140         ao_poly value;
141
142         if (!ao_scheme_check_argc(_ao_scheme_atom_sqrt, cons, 1, 1))
143                 return AO_SCHEME_NIL;
144         value = ao_scheme_arg(cons, 0);
145         if (!ao_scheme_number_typep(ao_scheme_poly_type(value)))
146                 return ao_scheme_error(AO_SCHEME_INVALID, "%s: non-numeric", ao_scheme_poly_atom(_ao_scheme_atom_sqrt)->name);
147         return ao_scheme_float_get(sqrtf(ao_scheme_poly_number(value)));
148 }