altos/scheme: Rework display/write code
[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 #ifdef AO_SCHEME_FEATURE_FLOAT
19
20 static void float_mark(void *addr)
21 {
22         (void) addr;
23 }
24
25 static int float_size(void *addr)
26 {
27         if (!addr)
28                 return 0;
29         return sizeof (struct ao_scheme_float);
30 }
31
32 static void float_move(void *addr)
33 {
34         (void) addr;
35 }
36
37 const struct ao_scheme_type ao_scheme_float_type = {
38         .mark = float_mark,
39         .size = float_size,
40         .move = float_move,
41         .name = "float",
42 };
43
44 #ifndef FLOAT_FORMAT
45 #define FLOAT_FORMAT "%g"
46 #endif
47
48 void
49 ao_scheme_float_write(ao_poly p, bool write)
50 {
51         struct ao_scheme_float *f = ao_scheme_poly_float(p);
52         float   v = f->value;
53
54         (void) write;
55         if (isnanf(v))
56                 printf("+nan.0");
57         else if (isinff(v)) {
58                 if (v < 0)
59                         printf("-");
60                 else
61                         printf("+");
62                 printf("inf.0");
63         } else
64                 printf (FLOAT_FORMAT, v);
65 }
66
67 float
68 ao_scheme_poly_number(ao_poly p)
69 {
70         switch (ao_scheme_poly_base_type(p)) {
71         case AO_SCHEME_INT:
72                 return ao_scheme_poly_int(p);
73         case AO_SCHEME_BIGINT:
74                 return ao_scheme_poly_bigint(p)->value;
75         case AO_SCHEME_OTHER:
76                 switch (ao_scheme_other_type(ao_scheme_poly_other(p))) {
77                 case AO_SCHEME_FLOAT:
78                         return ao_scheme_poly_float(p)->value;
79                 }
80         }
81         return NAN;
82 }
83
84 ao_poly
85 ao_scheme_float_get(float value)
86 {
87         struct ao_scheme_float  *f;
88
89         f = ao_scheme_alloc(sizeof (struct ao_scheme_float));
90         f->type = AO_SCHEME_FLOAT;
91         f->value = value;
92         return ao_scheme_float_poly(f);
93 }
94
95 ao_poly
96 ao_scheme_do_inexactp(struct ao_scheme_cons *cons)
97 {
98         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
99                 return AO_SCHEME_NIL;
100         if (ao_scheme_poly_type(ao_scheme_arg(cons, 0)) == AO_SCHEME_FLOAT)
101                 return _ao_scheme_bool_true;
102         return _ao_scheme_bool_false;
103 }
104
105 ao_poly
106 ao_scheme_do_finitep(struct ao_scheme_cons *cons)
107 {
108         ao_poly value;
109         float   f;
110
111         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
112                 return AO_SCHEME_NIL;
113         value = ao_scheme_arg(cons, 0);
114         switch (ao_scheme_poly_type(value)) {
115         case AO_SCHEME_INT:
116         case AO_SCHEME_BIGINT:
117                 return _ao_scheme_bool_true;
118         case AO_SCHEME_FLOAT:
119                 f = ao_scheme_poly_float(value)->value;
120                 if (!isnan(f) && !isinf(f))
121                         return _ao_scheme_bool_true;
122         }
123         return _ao_scheme_bool_false;
124 }
125
126 ao_poly
127 ao_scheme_do_infinitep(struct ao_scheme_cons *cons)
128 {
129         ao_poly value;
130         float   f;
131
132         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
133                 return AO_SCHEME_NIL;
134         value = ao_scheme_arg(cons, 0);
135         switch (ao_scheme_poly_type(value)) {
136         case AO_SCHEME_FLOAT:
137                 f = ao_scheme_poly_float(value)->value;
138                 if (isinf(f))
139                         return _ao_scheme_bool_true;
140         }
141         return _ao_scheme_bool_false;
142 }
143
144 ao_poly
145 ao_scheme_do_sqrt(struct ao_scheme_cons *cons)
146 {
147         ao_poly value;
148
149         if (!ao_scheme_check_argc(_ao_scheme_atom_sqrt, cons, 1, 1))
150                 return AO_SCHEME_NIL;
151         value = ao_scheme_arg(cons, 0);
152         if (!ao_scheme_number_typep(ao_scheme_poly_type(value)))
153                 return ao_scheme_error(AO_SCHEME_INVALID, "%s: non-numeric", ao_scheme_poly_atom(_ao_scheme_atom_sqrt)->name);
154         return ao_scheme_float_get(sqrtf(ao_scheme_poly_number(value)));
155 }
156 #endif