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 /* Conversion of trailing data to a double-precision floating point number. */ 32 33 static double __TOFLOAT(__attr attr) 34 { 35 return __get_trailing_data(attr, __builtins___float_float); 36 } 37 38 /* Numeric formatting using snprintf. 39 NOTE: This might be moved elsewhere and used by other types. */ 40 41 static __attr format_number(double n, int size) 42 { 43 char *s = (char *) __ALLOCATE(size, sizeof(char)); 44 int digits; 45 46 /* Allocation should raise a memory error if it fails, so this loop should 47 terminate via the return statement or an allocation failure. */ 48 49 while (1) 50 { 51 digits = snprintf(s, size, "%f", n); 52 53 if (digits < size) 54 { 55 s = (char *) __REALLOCATE(s, (digits + 1) * sizeof(char)); 56 return __new_str(s, digits); 57 } 58 59 size = digits + 1; 60 s = (char *) __REALLOCATE(s, size * sizeof(char)); 61 } 62 63 return __NULL; 64 } 65 66 static __attr make_result(__attr self, __attr other, double value) 67 { 68 __attr result; 69 70 if (self.value->temporary) 71 { 72 __set_trailing_data(self, __builtins___float_float, value); 73 return self; 74 } 75 else if (other.value->temporary) 76 { 77 __set_trailing_data(other, __builtins___float_float, value); 78 return other; 79 } 80 else 81 { 82 result = __new_float(value); 83 result.value->temporary = 1; 84 return result; 85 } 86 } 87 88 /* Floating point operations. Exceptions are raised in the signal handler. */ 89 90 __attr __fn_native_float_float_add(__attr __self, __attr self, __attr other) 91 { 92 /* self and other interpreted as float */ 93 double i = __TOFLOAT(self); 94 double j = __TOFLOAT(other); 95 return make_result(self, other, i + j); 96 } 97 98 __attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other) 99 { 100 /* self and other interpreted as float */ 101 double i = __TOFLOAT(self); 102 double j = __TOFLOAT(other); 103 return make_result(self, other, i - j); 104 } 105 106 __attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other) 107 { 108 /* self and other interpreted as float */ 109 double i = __TOFLOAT(self); 110 double j = __TOFLOAT(other); 111 return make_result(self, other, i * j); 112 } 113 114 __attr __fn_native_float_float_div(__attr __self, __attr self, __attr other) 115 { 116 /* self and other interpreted as float */ 117 double i = __TOFLOAT(self); 118 double j = __TOFLOAT(other); 119 return make_result(self, other, i / j); 120 } 121 122 __attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other) 123 { 124 /* self and other interpreted as float */ 125 double i = __TOFLOAT(self); 126 double j = __TOFLOAT(other); 127 return make_result(self, other, fmod(i, j)); 128 } 129 130 __attr __fn_native_float_float_neg(__attr __self, __attr self) 131 { 132 /* self interpreted as float */ 133 double i = __TOFLOAT(self); 134 return __new_float(-i); 135 } 136 137 __attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other) 138 { 139 /* self and other interpreted as float */ 140 double i = __TOFLOAT(self); 141 double j = __TOFLOAT(other); 142 double result; 143 144 errno = 0; 145 result = pow(i, j); 146 147 /* Test for overflow. */ 148 149 if (errno == ERANGE) 150 __raise_overflow_error(); 151 152 /* Return the result. */ 153 return make_result(self, other, result); 154 } 155 156 __attr __fn_native_float_float_le(__attr __self, __attr self, __attr other) 157 { 158 /* self and other interpreted as float */ 159 double i = __TOFLOAT(self); 160 double j = __TOFLOAT(other); 161 162 /* Return a boolean result. */ 163 return i <= j ? __builtins___boolean_True : __builtins___boolean_False; 164 } 165 166 __attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other) 167 { 168 /* self and other interpreted as float */ 169 double i = __TOFLOAT(self); 170 double j = __TOFLOAT(other); 171 172 /* Return a boolean result. */ 173 return i < j ? __builtins___boolean_True : __builtins___boolean_False; 174 } 175 176 __attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other) 177 { 178 /* self and other interpreted as float */ 179 double i = __TOFLOAT(self); 180 double j = __TOFLOAT(other); 181 182 /* Return a boolean result. */ 183 return i >= j ? __builtins___boolean_True : __builtins___boolean_False; 184 } 185 186 __attr __fn_native_float_float_gt(__attr __self, __attr self, __attr other) 187 { 188 /* self and other interpreted as float */ 189 double i = __TOFLOAT(self); 190 double j = __TOFLOAT(other); 191 192 /* Return a boolean result. */ 193 return i > j ? __builtins___boolean_True : __builtins___boolean_False; 194 } 195 196 __attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other) 197 { 198 /* self and other interpreted as float */ 199 double i = __TOFLOAT(self); 200 double j = __TOFLOAT(other); 201 202 /* Return a boolean result. */ 203 return i == j ? __builtins___boolean_True : __builtins___boolean_False; 204 } 205 206 __attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other) 207 { 208 /* self and other interpreted as float */ 209 double i = __TOFLOAT(self); 210 double j = __TOFLOAT(other); 211 212 /* Return a boolean result. */ 213 return i != j ? __builtins___boolean_True : __builtins___boolean_False; 214 } 215 216 __attr __fn_native_float_float_str(__attr __self, __attr self) 217 { 218 /* self interpreted as float */ 219 double i = __TOFLOAT(self); 220 221 /* Return a new string. */ 222 return format_number(i, 64); 223 } 224 225 __attr __fn_native_float_float_int(__attr __self, __attr self) 226 { 227 /* self interpreted as float */ 228 double i = __TOFLOAT(self); 229 230 /* NOTE: Test for conversion failure. */ 231 return __new_int((int) i); 232 } 233 234 /* Module initialisation. */ 235 236 void __main_native_float() 237 { 238 }