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 <gc/gc_inline.h> 23 #include "native/common.h" 24 #include "types.h" 25 #include "exceptions.h" 26 #include "ops.h" 27 #include "progconsts.h" 28 #include "progops.h" 29 #include "progtypes.h" 30 #include "main.h" 31 32 /* A list of preallocated float instances. */ 33 34 static void *preallocated_floats; 35 36 /* Preallocate some float instances. */ 37 38 #define MULTIPLE(VALUE, STEP) (((VALUE) + (STEP) - 1) & (~((STEP) - 1))) 39 #define PTRFREE 0 40 41 static void preallocate_floats() 42 { 43 GC_generic_malloc_many(MULTIPLE(__INSTANCESIZE(__builtins___float_float), GC_GRANULE_BYTES), 44 PTRFREE, &preallocated_floats); 45 } 46 47 static __attr new_float(double n) 48 { 49 __ref obj, next; 50 __attr attr; 51 52 if (!preallocated_floats) 53 preallocate_floats(); 54 55 obj = preallocated_floats; 56 57 /* Obtain the next object in the free list from the address in the first 58 word of the current object. */ 59 60 next = (__ref) *((void **) preallocated_floats); 61 62 /* Initialise the embedded instance. */ 63 64 __init(obj, 65 &__INSTANCETABLE(__builtins___float_float), 66 &__builtins___float_float); 67 68 /* Populate the float with the value. */ 69 70 attr = __ATTRVALUE(obj); 71 __set_trailing_data(attr, __builtins___float_float, n); 72 73 /* Make the next entry available and detach it from this one. */ 74 75 preallocated_floats = next; 76 77 return attr; 78 } 79 80 /* Conversion of trailing data to a double-precision floating point number. */ 81 82 static double __TOFLOAT(__attr attr) 83 { 84 return __get_trailing_data(attr, __builtins___float_float); 85 } 86 87 /* Numeric formatting using snprintf. 88 NOTE: This might be moved elsewhere and used by other types. */ 89 90 static __attr format_number(double n, int size) 91 { 92 char *s = (char *) __ALLOCATE(size, sizeof(char)); 93 int digits; 94 95 /* Allocation should raise a memory error if it fails, so this loop should 96 terminate via the return statement or an allocation failure. */ 97 98 while (1) 99 { 100 digits = snprintf(s, size, "%f", n); 101 102 if (digits < size) 103 { 104 s = (char *) __REALLOCATE(s, (digits + 1) * sizeof(char)); 105 return __new_str(s, digits); 106 } 107 108 size = digits + 1; 109 s = (char *) __REALLOCATE(s, size * sizeof(char)); 110 } 111 112 return __NULL; 113 } 114 115 /* Floating point operations. Exceptions are raised in the signal handler. */ 116 117 __attr __fn_native_float_float_add(__attr __self, __attr self, __attr other) 118 { 119 /* self and other interpreted as float */ 120 double i = __TOFLOAT(self); 121 double j = __TOFLOAT(other); 122 return new_float(i + j); 123 } 124 125 __attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other) 126 { 127 /* self and other interpreted as float */ 128 double i = __TOFLOAT(self); 129 double j = __TOFLOAT(other); 130 return new_float(i - j); 131 } 132 133 __attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other) 134 { 135 /* self and other interpreted as float */ 136 double i = __TOFLOAT(self); 137 double j = __TOFLOAT(other); 138 return new_float(i * j); 139 } 140 141 __attr __fn_native_float_float_div(__attr __self, __attr self, __attr other) 142 { 143 /* self and other interpreted as float */ 144 double i = __TOFLOAT(self); 145 double j = __TOFLOAT(other); 146 return new_float(i / j); 147 } 148 149 __attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other) 150 { 151 /* self and other interpreted as float */ 152 double i = __TOFLOAT(self); 153 double j = __TOFLOAT(other); 154 return new_float(fmod(i, j)); 155 } 156 157 __attr __fn_native_float_float_neg(__attr __self, __attr self) 158 { 159 /* self interpreted as float */ 160 double i = __TOFLOAT(self); 161 return new_float(-i); 162 } 163 164 __attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other) 165 { 166 /* self and other interpreted as float */ 167 double i = __TOFLOAT(self); 168 double j = __TOFLOAT(other); 169 double result; 170 171 errno = 0; 172 result = pow(i, j); 173 174 /* Test for overflow. */ 175 176 if (errno == ERANGE) 177 __raise_overflow_error(); 178 179 /* Return the result. */ 180 return new_float(result); 181 } 182 183 __attr __fn_native_float_float_le(__attr __self, __attr self, __attr other) 184 { 185 /* self and other interpreted as float */ 186 double i = __TOFLOAT(self); 187 double j = __TOFLOAT(other); 188 189 /* Return a boolean result. */ 190 return i <= j ? __builtins___boolean_True : __builtins___boolean_False; 191 } 192 193 __attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other) 194 { 195 /* self and other interpreted as float */ 196 double i = __TOFLOAT(self); 197 double j = __TOFLOAT(other); 198 199 /* Return a boolean result. */ 200 return i < j ? __builtins___boolean_True : __builtins___boolean_False; 201 } 202 203 __attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other) 204 { 205 /* self and other interpreted as float */ 206 double i = __TOFLOAT(self); 207 double j = __TOFLOAT(other); 208 209 /* Return a boolean result. */ 210 return i >= j ? __builtins___boolean_True : __builtins___boolean_False; 211 } 212 213 __attr __fn_native_float_float_gt(__attr __self, __attr self, __attr other) 214 { 215 /* self and other interpreted as float */ 216 double i = __TOFLOAT(self); 217 double j = __TOFLOAT(other); 218 219 /* Return a boolean result. */ 220 return i > j ? __builtins___boolean_True : __builtins___boolean_False; 221 } 222 223 __attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other) 224 { 225 /* self and other interpreted as float */ 226 double i = __TOFLOAT(self); 227 double j = __TOFLOAT(other); 228 229 /* Return a boolean result. */ 230 return i == j ? __builtins___boolean_True : __builtins___boolean_False; 231 } 232 233 __attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other) 234 { 235 /* self and other interpreted as float */ 236 double i = __TOFLOAT(self); 237 double j = __TOFLOAT(other); 238 239 /* Return a boolean result. */ 240 return i != j ? __builtins___boolean_True : __builtins___boolean_False; 241 } 242 243 __attr __fn_native_float_float_str(__attr __self, __attr self) 244 { 245 /* self interpreted as float */ 246 double i = __TOFLOAT(self); 247 248 /* Return a new string. */ 249 return format_number(i, 64); 250 } 251 252 __attr __fn_native_float_float_int(__attr __self, __attr self) 253 { 254 /* self interpreted as float */ 255 double i = __TOFLOAT(self); 256 257 /* NOTE: Test for conversion failure. */ 258 return __new_int((int) i); 259 } 260 261 /* Module initialisation. */ 262 263 void __main_native_float() 264 { 265 }