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 #ifndef FLOAT_FORMAT
43 #define FLOAT_FORMAT "%g"
44 #endif
45
46 void
47 ao_scheme_float_write(ao_poly p)
48 {
49         struct ao_scheme_float *f = ao_scheme_poly_float(p);
50         float   v = f->value;
51
52         if (isnanf(v))
53                 printf("+nan.0");
54         else if (isinff(v)) {
55                 if (v < 0)
56                         printf("-");
57                 else
58                         printf("+");
59                 printf("inf.0");
60         } else
61                 printf (FLOAT_FORMAT, v);
62 }
63
64 float
65 ao_scheme_poly_number(ao_poly p)
66 {
67         switch (ao_scheme_poly_base_type(p)) {
68         case AO_SCHEME_INT:
69                 return ao_scheme_poly_int(p);
70         case AO_SCHEME_OTHER:
71                 switch (ao_scheme_other_type(ao_scheme_poly_other(p))) {
72                 case AO_SCHEME_BIGINT:
73                         return ao_scheme_bigint_int(ao_scheme_poly_bigint(p)->value);
74                 case AO_SCHEME_FLOAT:
75                         return ao_scheme_poly_float(p)->value;
76                 }
77         }
78         return NAN;
79 }
80
81 ao_poly
82 ao_scheme_float_get(float value)
83 {
84         struct ao_scheme_float  *f;
85
86         f = ao_scheme_alloc(sizeof (struct ao_scheme_float));
87         f->type = AO_SCHEME_FLOAT;
88         f->value = value;
89         return ao_scheme_float_poly(f);
90 }
91
92 ao_poly
93 ao_scheme_do_inexactp(struct ao_scheme_cons *cons)
94 {
95         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
96                 return AO_SCHEME_NIL;
97         if (ao_scheme_poly_type(ao_scheme_arg(cons, 0)) == AO_SCHEME_FLOAT)
98                 return _ao_scheme_bool_true;
99         return _ao_scheme_bool_false;
100 }
101
102 ao_poly
103 ao_scheme_do_finitep(struct ao_scheme_cons *cons)
104 {
105         ao_poly value;
106         float   f;
107
108         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
109                 return AO_SCHEME_NIL;
110         value = ao_scheme_arg(cons, 0);
111         switch (ao_scheme_poly_type(value)) {
112         case AO_SCHEME_INT:
113         case AO_SCHEME_BIGINT:
114                 return _ao_scheme_bool_true;
115         case AO_SCHEME_FLOAT:
116                 f = ao_scheme_poly_float(value)->value;
117                 if (!isnan(f) && !isinf(f))
118                         return _ao_scheme_bool_true;
119         }
120         return _ao_scheme_bool_false;
121 }
122
123 ao_poly
124 ao_scheme_do_infinitep(struct ao_scheme_cons *cons)
125 {
126         ao_poly value;
127         float   f;
128
129         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
130                 return AO_SCHEME_NIL;
131         value = ao_scheme_arg(cons, 0);
132         switch (ao_scheme_poly_type(value)) {
133         case AO_SCHEME_FLOAT:
134                 f = ao_scheme_poly_float(value)->value;
135                 if (isinf(f))
136                         return _ao_scheme_bool_true;
137         }
138         return _ao_scheme_bool_false;
139 }
140
141 ao_poly
142 ao_scheme_do_sqrt(struct ao_scheme_cons *cons)
143 {
144         ao_poly value;
145
146         if (!ao_scheme_check_argc(_ao_scheme_atom_sqrt, cons, 1, 1))
147                 return AO_SCHEME_NIL;
148         value = ao_scheme_arg(cons, 0);
149         if (!ao_scheme_number_typep(ao_scheme_poly_type(value)))
150                 return ao_scheme_error(AO_SCHEME_INVALID, "%s: non-numeric", ao_scheme_poly_atom(_ao_scheme_atom_sqrt)->name);
151         return ao_scheme_float_get(sqrtf(ao_scheme_poly_number(value)));
152 }