1 module decimal.floats; 2 3 4 /* ****************************************************************************************************************** */ 5 /* FLOAT UTILITY FUNCTIONS */ 6 /* ****************************************************************************************************************** */ 7 8 private import decimal.integrals: uint128, clz, divrem; 9 10 package: 11 12 union FU 13 { 14 float f; 15 uint u; 16 } 17 18 @safe pure nothrow @nogc 19 float fpack(const bool sign, int exp, uint mantissa) 20 { 21 if (mantissa == 0) 22 return sign ? -0.0f : +0.0f; 23 auto shift = clz(mantissa) - 8; 24 if (shift < 0) 25 { 26 if (exp > int.max + shift) 27 return sign ? -float.infinity : +float.infinity; 28 else 29 mantissa >>= -shift; 30 } 31 else 32 { 33 if (exp < int.min + shift) 34 return sign ? -0.0f : +0.0f; 35 mantissa <<= shift; 36 } 37 exp -= shift; 38 39 if (exp > int.max - 150) 40 return sign ? -float.infinity : +float.infinity; 41 exp += 150; 42 43 if (exp >= 0xFF) 44 return sign ? -float.infinity : +float.infinity; 45 46 if (exp <= 0) 47 { 48 --exp; 49 if (exp < -23) 50 return sign ? -0.0f : +0.0f; 51 mantissa >>= -exp; 52 exp = 0; 53 } 54 55 FU fu; 56 fu.u = (mantissa & 0x7FFFFF) | (exp << 23); 57 if (sign) 58 fu.u |= 0x80000000U; 59 return fu.f; 60 } 61 62 @safe pure nothrow @nogc 63 bool funpack(const float f, out int exp, out uint mantissa, out bool inf, out bool nan) 64 { 65 FU fu; 66 fu.f = f; 67 68 exp = (fu.u >> 23) & 0xFF; 69 mantissa = fu.u & 0x7FFFFFU; 70 if (exp == 0) 71 { 72 inf = false; nan = false; 73 if (mantissa) 74 exp -= 149; 75 } 76 else if (exp == 0xFF) 77 { 78 inf = mantissa == 0; 79 nan = !inf; 80 } 81 else 82 { 83 inf = false; nan = false; 84 mantissa |= 0x00800000; 85 exp -= 150; 86 } 87 88 return (fu.u & 0x80000000U) != 0; 89 } 90 91 union DU 92 { 93 double d; 94 ulong u; 95 } 96 97 @safe pure nothrow @nogc 98 double dpack(const bool sign, int exp, ulong mantissa) 99 { 100 if (mantissa == 0) 101 return sign ? -0.0 : +0.0; 102 103 auto shift = clz(mantissa) - 11; 104 if (shift < 0) 105 { 106 if (exp > int.max + shift) 107 return sign ? -double.infinity : +double.infinity; 108 else 109 mantissa >>= -shift; 110 } 111 else 112 { 113 if (exp < int.min + shift) 114 return sign ? -0.0 : +0.0; 115 mantissa <<= shift; 116 } 117 exp -= shift; 118 119 if (exp > int.max - 1075) 120 return sign ? -double.infinity : +double.infinity; 121 exp += 1075; 122 123 if (exp >= 0x7FF) 124 return sign ? -double.infinity : +double.infinity; 125 126 if (exp <= 0) 127 { 128 --exp; 129 if (exp < -52) 130 return sign ? -0.0 : +0.0; 131 mantissa >>= -exp; 132 exp = 0; 133 } 134 135 DU du; 136 du.u = (mantissa & 0x000FFFFFFFFFFFFFUL) | (cast(ulong)exp << 52); 137 if (sign) 138 du.u |= 0x8000000000000000UL; 139 return du.d; 140 } 141 142 @safe pure nothrow @nogc 143 bool dunpack(const double d, out int exp, out ulong mantissa, out bool inf, out bool nan) 144 { 145 DU du; 146 du.d = d; 147 148 exp = (du.u >> 52) & 0x7FF; 149 mantissa = du.u & 0xFFFFFFFFFFFFF; 150 151 if (exp == 0) 152 { 153 inf = false; nan = false; 154 if (mantissa) 155 exp -= 1074; 156 } 157 else if (exp == 0x7FF) 158 { 159 inf = mantissa == 0; 160 nan = !inf; 161 } 162 else 163 { 164 inf = false; nan = false; 165 mantissa |= 0x10000000000000; 166 exp -= 1075; 167 } 168 169 return (du.u & 0x8000000000000000UL) != 0; 170 } 171 172 union RU 173 { 174 real r; 175 struct 176 { //align(1): 177 version(LittleEndian) 178 { 179 ulong m; 180 ushort e; 181 } 182 else 183 { 184 ushort e; 185 ulong m; 186 } 187 } 188 } 189 190 @safe pure nothrow @nogc 191 real rpack(const bool sign, int exp, ulong mantissa) 192 { 193 if (mantissa == 0) 194 return sign ? -0.0L : +0.0L; 195 196 auto shift = clz(mantissa); 197 if (exp < int.min + shift) 198 return sign ? -0.0L : +0.0L; 199 mantissa <<= shift; 200 exp -= shift; 201 202 if (exp > int.max - 16447) //16383 + 64 203 return sign ? -real.infinity : +real.infinity; 204 exp += 16447; 205 206 if (exp >= 0x7FFF) 207 return sign ? -real.infinity : +real.infinity; 208 209 if (exp <= 0) 210 { 211 --exp; 212 if (exp < -64) 213 return sign ? -0.0L : +0.0L; 214 mantissa >>= -exp; 215 exp = 0; 216 } 217 218 RU ru; 219 ru.m = mantissa; 220 ru.e = cast(ushort)exp; 221 if (sign) 222 ru.e |= 0x8000U; 223 return ru.r; 224 } 225 226 @safe pure nothrow @nogc 227 bool runpack(const real r, out int exp, out ulong mantissa, out bool inf, out bool nan) 228 { 229 RU ru; 230 ru.r = r; 231 232 exp = ru.e & 0x7FFF; 233 mantissa = ru.m; 234 235 if (exp == 0) 236 { 237 inf = false; nan = false; 238 if (mantissa) 239 exp -= 16445; 240 } 241 else if (exp == 0x7FFF) 242 { 243 inf = (mantissa & 0x7FFF_FFFF_FFFF_FFFF) == 0; 244 nan = !inf; 245 } 246 else 247 { 248 inf = false; nan = false; 249 exp -= 16446; 250 } 251 252 return (ru.e & 0x8000) != 0; 253 } 254 255 256 257 258 void floatExtract(float f, out uint coefficient, out int exponent) 259 { 260 // x * 2^n = y * 10^m -> 2^n = n * log2(10) 261 } 262 263 @nogc @safe pure nothrow 264 bool exp2to10(ref uint coefficient, ref int exponent) 265 { 266 enum maxMultiplicable = uint.max / 5U; 267 268 bool inexact; 269 270 auto e5 = -exponent; 271 272 273 274 while (e5 > 0) 275 { 276 if (!(coefficient & 1U)) 277 { 278 ++exponent; 279 --e5; 280 coefficient >>>= 1; 281 } 282 else 283 { 284 --e5; 285 if (coefficient <= maxMultiplicable) 286 coefficient *= 5U; 287 else 288 { 289 inexact = true; 290 ++exponent; 291 coefficient >>>= 1; 292 } 293 } 294 } 295 296 while (e5 < 0) 297 { 298 if ((coefficient & 0x80000000U) != 0x80000000U) 299 { 300 --exponent; 301 ++e5; 302 coefficient <<= 1; 303 } 304 else 305 { 306 ++e5; 307 if (coefficient % 5U != 0) 308 inexact = true; 309 coefficient /= 5U; 310 } 311 } 312 313 return inexact; 314 } 315 316 public 317 @nogc @safe pure nothrow 318 bool exp2to10(ref ulong coefficient, ref int exponent) 319 { 320 enum maxMultiplicable = ulong.max / 5UL; 321 322 bool inexact; 323 324 auto e5 = -exponent; 325 326 while (e5 > 0) 327 { 328 if (!(coefficient & 1UL)) 329 { 330 ++exponent; 331 --e5; 332 coefficient >>>= 1; 333 } 334 else 335 { 336 --e5; 337 if (coefficient <= maxMultiplicable) 338 coefficient *= 5UL; 339 else 340 { 341 inexact = true; 342 ++exponent; 343 coefficient >>>= 1; 344 } 345 } 346 } 347 348 while (e5 < 0) 349 { 350 if ((coefficient & 0x8000000000000000UL) != 0x8000000000000000UL) 351 { 352 --exponent; 353 ++e5; 354 coefficient <<= 1; 355 } 356 else 357 { 358 ++e5; 359 if (coefficient % 5UL != 0) 360 inexact = true; 361 coefficient /= 5UL; 362 } 363 } 364 365 return inexact; 366 } 367 368 @nogc @safe pure nothrow 369 bool exp2to10(ref uint128 coefficient, ref int exponent) 370 { 371 enum maxMultiplicable = uint128.max / 5UL; 372 373 bool inexact; 374 375 auto e5 = -exponent; 376 377 while (e5 > 0) 378 { 379 if (!(coefficient & 1UL)) 380 { 381 ++exponent; 382 --e5; 383 coefficient >>>= 1; 384 } 385 else 386 { 387 --e5; 388 if (coefficient <= maxMultiplicable) 389 coefficient *= 5U; 390 else 391 { 392 inexact = true; 393 ++exponent; 394 coefficient >>>= 1; 395 } 396 } 397 } 398 399 while (e5 < 0) 400 { 401 if ((coefficient.hi & 0x8000000000000000UL) != 0x8000000000000000UL) 402 { 403 --exponent; 404 ++e5; 405 coefficient <<= 1; 406 } 407 else 408 { 409 ++e5; 410 if (divrem(coefficient, 5U)) 411 inexact = true; 412 } 413 } 414 415 return inexact; 416 } 417 418