1 /* Native functions for floating point operations. 2 3 Copyright (C) 2016, 2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk> 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT 11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 details. 14 15 You should have received a copy of the GNU General Public License along with 16 this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <math.h> /* pow */ 20 #include <stdio.h> /* snprintf */ 21 #include <errno.h> /* errno */ 22 #include "native/common.h" 23 #include "types.h" 24 #include "exceptions.h" 25 #include "ops.h" 26 #include "progconsts.h" 27 #include "progops.h" 28 #include "progtypes.h" 29 #include "main.h" 30 31 /* A table of preallocated float instances. */ 32 33 struct float_table 34 { 35 struct float_table *next; 36 char data[]; 37 }; 38 39 static struct float_table *next_float = 0; 40 41 /* Preallocate some float instances. */ 42 43 static void preallocate_floats(int num) 44 { 45 struct float_table *latest; 46 int i; 47 48 for (i = 0; i < num; i++) 49 { 50 /* Allocate a table entry. */ 51 52 latest = (struct float_table *) 53 __ALLOCATE(1, sizeof(struct float_table *) + 54 __INSTANCESIZE(__builtins___float_float)); 55 56 /* Reference the last entry from the new entry. */ 57 58 latest->next = next_float; 59 next_float = latest; 60 } 61 } 62 63 static __attr new_float(double n) 64 { 65 struct float_table *this_float; 66 __attr attr; 67 68 if (!next_float) 69 preallocate_floats(1000); 70 71 /* Reference the next preallocated entry. */ 72 73 this_float = next_float; 74 75 /* Initialise the embedded instance. */ 76 77 __init((__ref) &this_float->data, 78 &__INSTANCETABLE(__builtins___float_float), 79 &__builtins___float_float); 80 81 /* Populate the float with the value. */ 82 83 attr = __ATTRVALUE(&this_float->data); 84 __set_trailing_data(attr, __builtins___float_float, n); 85 86 /* Make the next entry available and detach it from this one. */ 87 88 next_float = this_float->next; 89 this_float->next = 0; 90 91 return attr; 92 } 93 94 /* Conversion of trailing data to a double-precision floating point number. */ 95 96 static double __TOFLOAT(__attr attr) 97 { 98 return __get_trailing_data(attr, __builtins___float_float); 99 } 100 101 /* Numeric formatting using snprintf. 102 NOTE: This might be moved elsewhere and used by other types. */ 103 104 static __attr format_number(double n, int size) 105 { 106 char *s = (char *) __ALLOCATE(size, sizeof(char)); 107 int digits; 108 109 /* Allocation should raise a memory error if it fails, so this loop should 110 terminate via the return statement or an allocation failure. */ 111 112 while (1) 113 { 114 digits = snprintf(s, size, "%f", n); 115 116 if (digits < size) 117 { 118 s = (char *) __REALLOCATE(s, (digits + 1) * sizeof(char)); 119 return __new_str(s, digits); 120 } 121 122 size = digits + 1; 123 s = (char *) __REALLOCATE(s, size * sizeof(char)); 124 } 125 126 return __NULL; 127 } 128 129 /* Floating point operations. Exceptions are raised in the signal handler. */ 130 131 __attr __fn_native_float_float_add(__attr __self, __attr self, __attr other) 132 { 133 /* self and other interpreted as float */ 134 double i = __TOFLOAT(self); 135 double j = __TOFLOAT(other); 136 return new_float(i + j); 137 } 138 139 __attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other) 140 { 141 /* self and other interpreted as float */ 142 double i = __TOFLOAT(self); 143 double j = __TOFLOAT(other); 144 return new_float(i - j); 145 } 146 147 __attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other) 148 { 149 /* self and other interpreted as float */ 150 double i = __TOFLOAT(self); 151 double j = __TOFLOAT(other); 152 return new_float(i * j); 153 } 154 155 __attr __fn_native_float_float_div(__attr __self, __attr self, __attr other) 156 { 157 /* self and other interpreted as float */ 158 double i = __TOFLOAT(self); 159 double j = __TOFLOAT(other); 160 return new_float(i / j); 161 } 162 163 __attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other) 164 { 165 /* self and other interpreted as float */ 166 double i = __TOFLOAT(self); 167 double j = __TOFLOAT(other); 168 return new_float(fmod(i, j)); 169 } 170 171 __attr __fn_native_float_float_neg(__attr __self, __attr self) 172 { 173 /* self interpreted as float */ 174 double i = __TOFLOAT(self); 175 return new_float(-i); 176 } 177 178 __attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other) 179 { 180 /* self and other interpreted as float */ 181 double i = __TOFLOAT(self); 182 double j = __TOFLOAT(other); 183 double result; 184 185 errno = 0; 186 result = pow(i, j); 187 188 /* Test for overflow. */ 189 190 if (errno == ERANGE) 191 __raise_overflow_error(); 192 193 /* Return the result. */ 194 return new_float(result); 195 } 196 197 __attr __fn_native_float_float_le(__attr __self, __attr self, __attr other) 198 { 199 /* self and other interpreted as float */ 200 double i = __TOFLOAT(self); 201 double j = __TOFLOAT(other); 202 203 /* Return a boolean result. */ 204 return i <= j ? __builtins___boolean_True : __builtins___boolean_False; 205 } 206 207 __attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other) 208 { 209 /* self and other interpreted as float */ 210 double i = __TOFLOAT(self); 211 double j = __TOFLOAT(other); 212 213 /* Return a boolean result. */ 214 return i < j ? __builtins___boolean_True : __builtins___boolean_False; 215 } 216 217 __attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other) 218 { 219 /* self and other interpreted as float */ 220 double i = __TOFLOAT(self); 221 double j = __TOFLOAT(other); 222 223 /* Return a boolean result. */ 224 return i >= j ? __builtins___boolean_True : __builtins___boolean_False; 225 } 226 227 __attr __fn_native_float_float_gt(__attr __self, __attr self, __attr other) 228 { 229 /* self and other interpreted as float */ 230 double i = __TOFLOAT(self); 231 double j = __TOFLOAT(other); 232 233 /* Return a boolean result. */ 234 return i > j ? __builtins___boolean_True : __builtins___boolean_False; 235 } 236 237 __attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other) 238 { 239 /* self and other interpreted as float */ 240 double i = __TOFLOAT(self); 241 double j = __TOFLOAT(other); 242 243 /* Return a boolean result. */ 244 return i == j ? __builtins___boolean_True : __builtins___boolean_False; 245 } 246 247 __attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other) 248 { 249 /* self and other interpreted as float */ 250 double i = __TOFLOAT(self); 251 double j = __TOFLOAT(other); 252 253 /* Return a boolean result. */ 254 return i != j ? __builtins___boolean_True : __builtins___boolean_False; 255 } 256 257 __attr __fn_native_float_float_str(__attr __self, __attr self) 258 { 259 /* self interpreted as float */ 260 double i = __TOFLOAT(self); 261 262 /* Return a new string. */ 263 return format_number(i, 64); 264 } 265 266 __attr __fn_native_float_float_int(__attr __self, __attr self) 267 { 268 /* self interpreted as float */ 269 double i = __TOFLOAT(self); 270 271 /* NOTE: Test for conversion failure. */ 272 return __new_int((int) i); 273 } 274 275 /* Module initialisation. */ 276 277 void __main_native_float() 278 { 279 }