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 /* Floating point operations. Exceptions are raised in the signal handler. */ 67 68 __attr __fn_native_float_float_add(__attr __self, __attr self, __attr other) 69 { 70 /* self and other interpreted as float */ 71 double i = __TOFLOAT(self); 72 double j = __TOFLOAT(other); 73 return __new_float(i + j); 74 } 75 76 __attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other) 77 { 78 /* self and other interpreted as float */ 79 double i = __TOFLOAT(self); 80 double j = __TOFLOAT(other); 81 return __new_float(i - j); 82 } 83 84 __attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other) 85 { 86 /* self and other interpreted as float */ 87 double i = __TOFLOAT(self); 88 double j = __TOFLOAT(other); 89 return __new_float(i * j); 90 } 91 92 __attr __fn_native_float_float_div(__attr __self, __attr self, __attr other) 93 { 94 /* self and other interpreted as float */ 95 double i = __TOFLOAT(self); 96 double j = __TOFLOAT(other); 97 return __new_float(i / j); 98 } 99 100 __attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other) 101 { 102 /* self and other interpreted as float */ 103 double i = __TOFLOAT(self); 104 double j = __TOFLOAT(other); 105 return __new_float(fmod(i, j)); 106 } 107 108 __attr __fn_native_float_float_neg(__attr __self, __attr self) 109 { 110 /* self interpreted as float */ 111 double i = __TOFLOAT(self); 112 return __new_float(-i); 113 } 114 115 __attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other) 116 { 117 /* self and other interpreted as float */ 118 double i = __TOFLOAT(self); 119 double j = __TOFLOAT(other); 120 double result; 121 122 errno = 0; 123 result = pow(i, j); 124 125 /* Test for overflow. */ 126 127 if (errno == ERANGE) 128 __raise_overflow_error(); 129 130 /* Return the result. */ 131 return __new_float(result); 132 } 133 134 __attr __fn_native_float_float_le(__attr __self, __attr self, __attr other) 135 { 136 /* self and other interpreted as float */ 137 double i = __TOFLOAT(self); 138 double j = __TOFLOAT(other); 139 140 /* Return a boolean result. */ 141 return i <= j ? __builtins___boolean_True : __builtins___boolean_False; 142 } 143 144 __attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other) 145 { 146 /* self and other interpreted as float */ 147 double i = __TOFLOAT(self); 148 double j = __TOFLOAT(other); 149 150 /* Return a boolean result. */ 151 return i < j ? __builtins___boolean_True : __builtins___boolean_False; 152 } 153 154 __attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other) 155 { 156 /* self and other interpreted as float */ 157 double i = __TOFLOAT(self); 158 double j = __TOFLOAT(other); 159 160 /* Return a boolean result. */ 161 return i >= j ? __builtins___boolean_True : __builtins___boolean_False; 162 } 163 164 __attr __fn_native_float_float_gt(__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 170 /* Return a boolean result. */ 171 return i > j ? __builtins___boolean_True : __builtins___boolean_False; 172 } 173 174 __attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other) 175 { 176 /* self and other interpreted as float */ 177 double i = __TOFLOAT(self); 178 double j = __TOFLOAT(other); 179 180 /* Return a boolean result. */ 181 return i == j ? __builtins___boolean_True : __builtins___boolean_False; 182 } 183 184 __attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other) 185 { 186 /* self and other interpreted as float */ 187 double i = __TOFLOAT(self); 188 double j = __TOFLOAT(other); 189 190 /* Return a boolean result. */ 191 return i != j ? __builtins___boolean_True : __builtins___boolean_False; 192 } 193 194 __attr __fn_native_float_float_str(__attr __self, __attr self) 195 { 196 /* self interpreted as float */ 197 double i = __TOFLOAT(self); 198 199 /* Return a new string. */ 200 return format_number(i, 64); 201 } 202 203 __attr __fn_native_float_float_int(__attr __self, __attr self) 204 { 205 /* self interpreted as float */ 206 double i = __TOFLOAT(self); 207 208 /* NOTE: Test for conversion failure. */ 209 return __new_int((int) i); 210 } 211 212 /* Module initialisation. */ 213 214 void __main_native_float() 215 { 216 }