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 #define NUM_PREALLOCATED 10000 34 35 static __ref preallocated_floats; 36 static int floats_left = 0; 37 38 /* Preallocate some float instances. */ 39 40 static void preallocate_floats() 41 { 42 preallocated_floats = __ALLOCATEIM(NUM_PREALLOCATED, __INSTANCESIZE(__builtins___float_float)); 43 floats_left = NUM_PREALLOCATED; 44 } 45 46 static __attr new_float(double n) 47 { 48 __ref obj; 49 __attr attr; 50 51 if (!floats_left) 52 preallocate_floats(); 53 54 floats_left--; 55 obj = preallocated_floats; 56 57 /* Initialise the instance. */ 58 59 __init(obj, &__INSTANCETABLE(__builtins___float_float), 60 &__builtins___float_float); 61 62 /* Populate the float with the value. */ 63 64 attr = __ATTRVALUE(obj); 65 __set_trailing_data(attr, __builtins___float_float, n); 66 67 /* Reference the next float. */ 68 69 preallocated_floats = (__ref) ((char *) preallocated_floats + __INSTANCESIZE(__builtins___float_float)); 70 71 return attr; 72 } 73 74 /* Conversion of trailing data to a double-precision floating point number. */ 75 76 static double __TOFLOAT(__attr attr) 77 { 78 return __get_trailing_data(attr, __builtins___float_float); 79 } 80 81 /* Numeric formatting using snprintf. 82 NOTE: This might be moved elsewhere and used by other types. */ 83 84 static __attr format_number(double n, int size) 85 { 86 char *s = (char *) __ALLOCATE(size, sizeof(char)); 87 int digits; 88 89 /* Allocation should raise a memory error if it fails, so this loop should 90 terminate via the return statement or an allocation failure. */ 91 92 while (1) 93 { 94 digits = snprintf(s, size, "%f", n); 95 96 if (digits < size) 97 { 98 s = (char *) __REALLOCATE(s, (digits + 1) * sizeof(char)); 99 return __new_str(s, digits); 100 } 101 102 size = digits + 1; 103 s = (char *) __REALLOCATE(s, size * sizeof(char)); 104 } 105 106 return __NULL; 107 } 108 109 /* Floating point operations. Exceptions are raised in the signal handler. */ 110 111 __attr __fn_native_float_float_add(__attr __self, __attr self, __attr other) 112 { 113 /* self and other interpreted as float */ 114 double i = __TOFLOAT(self); 115 double j = __TOFLOAT(other); 116 return new_float(i + j); 117 } 118 119 __attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other) 120 { 121 /* self and other interpreted as float */ 122 double i = __TOFLOAT(self); 123 double j = __TOFLOAT(other); 124 return new_float(i - j); 125 } 126 127 __attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other) 128 { 129 /* self and other interpreted as float */ 130 double i = __TOFLOAT(self); 131 double j = __TOFLOAT(other); 132 return new_float(i * j); 133 } 134 135 __attr __fn_native_float_float_div(__attr __self, __attr self, __attr other) 136 { 137 /* self and other interpreted as float */ 138 double i = __TOFLOAT(self); 139 double j = __TOFLOAT(other); 140 return new_float(i / j); 141 } 142 143 __attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other) 144 { 145 /* self and other interpreted as float */ 146 double i = __TOFLOAT(self); 147 double j = __TOFLOAT(other); 148 return new_float(fmod(i, j)); 149 } 150 151 __attr __fn_native_float_float_neg(__attr __self, __attr self) 152 { 153 /* self interpreted as float */ 154 double i = __TOFLOAT(self); 155 return new_float(-i); 156 } 157 158 __attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other) 159 { 160 /* self and other interpreted as float */ 161 double i = __TOFLOAT(self); 162 double j = __TOFLOAT(other); 163 double result; 164 165 errno = 0; 166 result = pow(i, j); 167 168 /* Test for overflow. */ 169 170 if (errno == ERANGE) 171 __raise_overflow_error(); 172 173 /* Return the result. */ 174 return new_float(result); 175 } 176 177 __attr __fn_native_float_float_le(__attr __self, __attr self, __attr other) 178 { 179 /* self and other interpreted as float */ 180 double i = __TOFLOAT(self); 181 double j = __TOFLOAT(other); 182 183 /* Return a boolean result. */ 184 return i <= j ? __builtins___boolean_True : __builtins___boolean_False; 185 } 186 187 __attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other) 188 { 189 /* self and other interpreted as float */ 190 double i = __TOFLOAT(self); 191 double j = __TOFLOAT(other); 192 193 /* Return a boolean result. */ 194 return i < j ? __builtins___boolean_True : __builtins___boolean_False; 195 } 196 197 __attr __fn_native_float_float_ge(__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_gt(__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_eq(__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_ne(__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_str(__attr __self, __attr self) 238 { 239 /* self interpreted as float */ 240 double i = __TOFLOAT(self); 241 242 /* Return a new string. */ 243 return format_number(i, 64); 244 } 245 246 __attr __fn_native_float_float_int(__attr __self, __attr self) 247 { 248 /* self interpreted as float */ 249 double i = __TOFLOAT(self); 250 251 /* NOTE: Test for conversion failure. */ 252 return __new_int((int) i); 253 } 254 255 /* Module initialisation. */ 256 257 void __main_native_float() 258 { 259 }