| author | |
| committer | |
| log | 41dd2beaacade94c5c98400a4a655aea07b9e2f3 |
| tree | d7cd75c3ded0e8517e801f62dbb883d93f3cd585 |
| parent | 6f4343b61afe36a709e713735947561a2b76bce8 |
* unify the logic for exporting math functions from compiler-rt,
with the appropriate suffixes and prefixes.
- add all missing f128 and f80 exports. Functions with missing
implementations call other functions and have TODO comments.
- also add f16 functions
* move math functions from freestanding libc to compiler-rt (#7265)
* enable all the f128 and f80 code in the stage2 compiler and behavior
tests (#11161).
* update std lib to use builtins rather than `std.math`.78 files changed, 4768 insertions(+), 5020 deletions(-)
CMakeLists.txt+33-1| ... | ... | @@ -445,7 +445,6 @@ set(ZIG_STAGE2_SOURCES |
| 445 | 445 | "${CMAKE_SOURCE_DIR}/lib/std/math/big.zig" |
| 446 | 446 | "${CMAKE_SOURCE_DIR}/lib/std/math/big/int.zig" |
| 447 | 447 | "${CMAKE_SOURCE_DIR}/lib/std/math/float.zig" |
| 448 | "${CMAKE_SOURCE_DIR}/lib/std/math/floor.zig" | |
| 449 | 448 | "${CMAKE_SOURCE_DIR}/lib/std/math/frexp.zig" |
| 450 | 449 | "${CMAKE_SOURCE_DIR}/lib/std/math/isinf.zig" |
| 451 | 450 | "${CMAKE_SOURCE_DIR}/lib/std/math/isnan.zig" |
| ... | ... | @@ -482,20 +481,40 @@ set(ZIG_STAGE2_SOURCES |
| 482 | 481 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig" |
| 483 | 482 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/absv.zig" |
| 484 | 483 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addXf3.zig" |
| 484 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addo.zig" | |
| 485 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/arm.zig" | |
| 485 | 486 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/atomics.zig" |
| 487 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/aulldiv.zig" | |
| 488 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/aullrem.zig" | |
| 486 | 489 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/bswap.zig" |
| 490 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/ceil.zig" | |
| 487 | 491 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/clear_cache.zig" |
| 488 | 492 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/cmp.zig" |
| 489 | 493 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/compareXf2.zig" |
| 494 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/cos.zig" | |
| 490 | 495 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/count0bits.zig" |
| 491 | 496 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divdf3.zig" |
| 492 | 497 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divsf3.zig" |
| 493 | 498 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divtf3.zig" |
| 494 | 499 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divti3.zig" |
| 500 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divxf3.zig" | |
| 501 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/emutls.zig" | |
| 502 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/exp.zig" | |
| 503 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/exp2.zig" | |
| 495 | 504 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/extendXfYf2.zig" |
| 505 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/extend_f80.zig" | |
| 506 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fabs.zig" | |
| 496 | 507 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixXfYi.zig" |
| 497 | 508 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatXiYf.zig" |
| 509 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floor.zig" | |
| 510 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fma.zig" | |
| 511 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fmax.zig" | |
| 512 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fmin.zig" | |
| 513 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fmod.zig" | |
| 498 | 514 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/int.zig" |
| 515 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/log.zig" | |
| 516 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/log10.zig" | |
| 517 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/log2.zig" | |
| 499 | 518 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/modti3.zig" |
| 500 | 519 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulXf3.zig" |
| 501 | 520 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muldi3.zig" |
| ... | ... | @@ -507,9 +526,22 @@ set(ZIG_STAGE2_SOURCES |
| 507 | 526 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/os_version_check.zig" |
| 508 | 527 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/parity.zig" |
| 509 | 528 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/popcount.zig" |
| 529 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/rem_pio2.zig" | |
| 530 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/rem_pio2_large.zig" | |
| 531 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/rem_pio2f.zig" | |
| 532 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/round.zig" | |
| 510 | 533 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/shift.zig" |
| 534 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/sin.zig" | |
| 535 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/sincos.zig" | |
| 536 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/sparc.zig" | |
| 537 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/sqrt.zig" | |
| 511 | 538 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/stack_probe.zig" |
| 539 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/subo.zig" | |
| 540 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/tan.zig" | |
| 541 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/trig.zig" | |
| 542 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/trunc.zig" | |
| 512 | 543 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/truncXfYf2.zig" |
| 544 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/trunc_f80.zig" | |
| 513 | 545 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmod.zig" |
| 514 | 546 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmodti4.zig" |
| 515 | 547 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivti3.zig" |
lib/std/fmt/errol.zig+4-4| ... | ... | @@ -113,7 +113,7 @@ fn errolSlow(val: f64, buffer: []u8) FloatDecimal { |
| 113 | 113 | // normalize the midpoint |
| 114 | 114 | |
| 115 | 115 | const e = math.frexp(val).exponent; |
| 116 | var exp = @floatToInt(i16, math.floor(307 + @intToFloat(f64, e) * 0.30103)); | |
| 116 | var exp = @floatToInt(i16, @floor(307 + @intToFloat(f64, e) * 0.30103)); | |
| 117 | 117 | if (exp < 20) { |
| 118 | 118 | exp = 20; |
| 119 | 119 | } else if (@intCast(usize, exp) >= lookup_table.len) { |
| ... | ... | @@ -170,10 +170,10 @@ fn errolSlow(val: f64, buffer: []u8) FloatDecimal { |
| 170 | 170 | // digit generation |
| 171 | 171 | var buf_index: usize = 0; |
| 172 | 172 | while (true) { |
| 173 | var hdig = @floatToInt(u8, math.floor(high.val)); | |
| 173 | var hdig = @floatToInt(u8, @floor(high.val)); | |
| 174 | 174 | if ((high.val == @intToFloat(f64, hdig)) and (high.off < 0)) hdig -= 1; |
| 175 | 175 | |
| 176 | var ldig = @floatToInt(u8, math.floor(low.val)); | |
| 176 | var ldig = @floatToInt(u8, @floor(low.val)); | |
| 177 | 177 | if ((low.val == @intToFloat(f64, ldig)) and (low.off < 0)) ldig -= 1; |
| 178 | 178 | |
| 179 | 179 | if (ldig != hdig) break; |
| ... | ... | @@ -187,7 +187,7 @@ fn errolSlow(val: f64, buffer: []u8) FloatDecimal { |
| 187 | 187 | } |
| 188 | 188 | |
| 189 | 189 | const tmp = (high.val + low.val) / 2.0; |
| 190 | var mdig = @floatToInt(u8, math.floor(tmp + 0.5)); | |
| 190 | var mdig = @floatToInt(u8, @floor(tmp + 0.5)); | |
| 191 | 191 | if ((@intToFloat(f64, mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1; |
| 192 | 192 | |
| 193 | 193 | buffer[buf_index] = mdig + '0'; |
lib/std/math.zig+2-29| ... | ... | @@ -138,7 +138,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { |
| 138 | 138 | if (isNan(x) or isNan(y)) |
| 139 | 139 | return false; |
| 140 | 140 | |
| 141 | return fabs(x - y) <= tolerance; | |
| 141 | return @fabs(x - y) <= tolerance; | |
| 142 | 142 | } |
| 143 | 143 | |
| 144 | 144 | /// Performs an approximate comparison of two floating point values `x` and `y`. |
| ... | ... | @@ -166,7 +166,7 @@ pub fn approxEqRel(comptime T: type, x: T, y: T, tolerance: T) bool { |
| 166 | 166 | if (isNan(x) or isNan(y)) |
| 167 | 167 | return false; |
| 168 | 168 | |
| 169 | return fabs(x - y) <= max(fabs(x), fabs(y)) * tolerance; | |
| 169 | return @fabs(x - y) <= max(@fabs(x), @fabs(y)) * tolerance; | |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | pub fn approxEq(comptime T: type, x: T, y: T, tolerance: T) bool { |
| ... | ... | @@ -233,11 +233,6 @@ pub fn raiseDivByZero() void { |
| 233 | 233 | |
| 234 | 234 | pub const isNan = @import("math/isnan.zig").isNan; |
| 235 | 235 | pub const isSignalNan = @import("math/isnan.zig").isSignalNan; |
| 236 | pub const fabs = @import("math/fabs.zig").fabs; | |
| 237 | pub const ceil = @import("math/ceil.zig").ceil; | |
| 238 | pub const floor = @import("math/floor.zig").floor; | |
| 239 | pub const trunc = @import("math/trunc.zig").trunc; | |
| 240 | pub const round = @import("math/round.zig").round; | |
| 241 | 236 | pub const frexp = @import("math/frexp.zig").frexp; |
| 242 | 237 | pub const Frexp = @import("math/frexp.zig").Frexp; |
| 243 | 238 | pub const modf = @import("math/modf.zig").modf; |
| ... | ... | @@ -261,8 +256,6 @@ pub const asin = @import("math/asin.zig").asin; |
| 261 | 256 | pub const atan = @import("math/atan.zig").atan; |
| 262 | 257 | pub const atan2 = @import("math/atan2.zig").atan2; |
| 263 | 258 | pub const hypot = @import("math/hypot.zig").hypot; |
| 264 | pub const exp = @import("math/exp.zig").exp; | |
| 265 | pub const exp2 = @import("math/exp2.zig").exp2; | |
| 266 | 259 | pub const expm1 = @import("math/expm1.zig").expm1; |
| 267 | 260 | pub const ilogb = @import("math/ilogb.zig").ilogb; |
| 268 | 261 | pub const ln = @import("math/ln.zig").ln; |
| ... | ... | @@ -270,16 +263,12 @@ pub const log = @import("math/log.zig").log; |
| 270 | 263 | pub const log2 = @import("math/log2.zig").log2; |
| 271 | 264 | pub const log10 = @import("math/log10.zig").log10; |
| 272 | 265 | pub const log1p = @import("math/log1p.zig").log1p; |
| 273 | pub const fma = @import("math/fma.zig").fma; | |
| 274 | 266 | pub const asinh = @import("math/asinh.zig").asinh; |
| 275 | 267 | pub const acosh = @import("math/acosh.zig").acosh; |
| 276 | 268 | pub const atanh = @import("math/atanh.zig").atanh; |
| 277 | 269 | pub const sinh = @import("math/sinh.zig").sinh; |
| 278 | 270 | pub const cosh = @import("math/cosh.zig").cosh; |
| 279 | 271 | pub const tanh = @import("math/tanh.zig").tanh; |
| 280 | pub const cos = @import("math/cos.zig").cos; | |
| 281 | pub const sin = @import("math/sin.zig").sin; | |
| 282 | pub const tan = @import("math/tan.zig").tan; | |
| 283 | 272 | |
| 284 | 273 | pub const complex = @import("math/complex.zig"); |
| 285 | 274 | pub const Complex = complex.Complex; |
| ... | ... | @@ -716,17 +705,6 @@ fn testAbsInt() !void { |
| 716 | 705 | try testing.expect((absInt(@as(i32, 10)) catch unreachable) == 10); |
| 717 | 706 | } |
| 718 | 707 | |
| 719 | pub const absFloat = fabs; | |
| 720 | ||
| 721 | test "absFloat" { | |
| 722 | try testAbsFloat(); | |
| 723 | comptime try testAbsFloat(); | |
| 724 | } | |
| 725 | fn testAbsFloat() !void { | |
| 726 | try testing.expect(absFloat(@as(f32, -10.05)) == 10.05); | |
| 727 | try testing.expect(absFloat(@as(f32, 10.05)) == 10.05); | |
| 728 | } | |
| 729 | ||
| 730 | 708 | /// Divide numerator by denominator, rounding toward zero. Returns an |
| 731 | 709 | /// error on overflow or when denominator is zero. |
| 732 | 710 | pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { |
| ... | ... | @@ -1400,11 +1378,6 @@ test "order.compare" { |
| 1400 | 1378 | try testing.expect(order(1, 0).compare(.neq)); |
| 1401 | 1379 | } |
| 1402 | 1380 | |
| 1403 | test "comptime sin and ln" { | |
| 1404 | const v = comptime (sin(@as(f32, 1)) + ln(@as(f32, 5))); | |
| 1405 | try testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5))); | |
| 1406 | } | |
| 1407 | ||
| 1408 | 1381 | /// Returns a mask of all ones if value is true, |
| 1409 | 1382 | /// and a mask of all zeroes if value is false. |
| 1410 | 1383 | /// Compiles to one instruction for register sized integers. |
lib/std/math/__rem_pio2.zig deleted-198| ... | ... | @@ -1,198 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__rem_pio2.c | |
| 5 | ||
| 6 | const std = @import("../std.zig"); | |
| 7 | const __rem_pio2_large = @import("__rem_pio2_large.zig").__rem_pio2_large; | |
| 8 | const math = std.math; | |
| 9 | ||
| 10 | const toint = 1.5 / math.floatEps(f64); | |
| 11 | // pi/4 | |
| 12 | const pio4 = 0x1.921fb54442d18p-1; | |
| 13 | // invpio2: 53 bits of 2/pi | |
| 14 | const invpio2 = 6.36619772367581382433e-01; // 0x3FE45F30, 0x6DC9C883 | |
| 15 | // pio2_1: first 33 bit of pi/2 | |
| 16 | const pio2_1 = 1.57079632673412561417e+00; // 0x3FF921FB, 0x54400000 | |
| 17 | // pio2_1t: pi/2 - pio2_1 | |
| 18 | const pio2_1t = 6.07710050650619224932e-11; // 0x3DD0B461, 0x1A626331 | |
| 19 | // pio2_2: second 33 bit of pi/2 | |
| 20 | const pio2_2 = 6.07710050630396597660e-11; // 0x3DD0B461, 0x1A600000 | |
| 21 | // pio2_2t: pi/2 - (pio2_1+pio2_2) | |
| 22 | const pio2_2t = 2.02226624879595063154e-21; // 0x3BA3198A, 0x2E037073 | |
| 23 | // pio2_3: third 33 bit of pi/2 | |
| 24 | const pio2_3 = 2.02226624871116645580e-21; // 0x3BA3198A, 0x2E000000 | |
| 25 | // pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) | |
| 26 | const pio2_3t = 8.47842766036889956997e-32; // 0x397B839A, 0x252049C1 | |
| 27 | ||
| 28 | fn U(x: anytype) usize { | |
| 29 | return @intCast(usize, x); | |
| 30 | } | |
| 31 | ||
| 32 | fn medium(ix: u32, x: f64, y: *[2]f64) i32 { | |
| 33 | var w: f64 = undefined; | |
| 34 | var t: f64 = undefined; | |
| 35 | var r: f64 = undefined; | |
| 36 | var @"fn": f64 = undefined; | |
| 37 | var n: i32 = undefined; | |
| 38 | var ex: i32 = undefined; | |
| 39 | var ey: i32 = undefined; | |
| 40 | var ui: u64 = undefined; | |
| 41 | ||
| 42 | // rint(x/(pi/2)) | |
| 43 | @"fn" = x * invpio2 + toint - toint; | |
| 44 | n = @floatToInt(i32, @"fn"); | |
| 45 | r = x - @"fn" * pio2_1; | |
| 46 | w = @"fn" * pio2_1t; // 1st round, good to 85 bits | |
| 47 | // Matters with directed rounding. | |
| 48 | if (r - w < -pio4) { | |
| 49 | n -= 1; | |
| 50 | @"fn" -= 1; | |
| 51 | r = x - @"fn" * pio2_1; | |
| 52 | w = @"fn" * pio2_1t; | |
| 53 | } else if (r - w > pio4) { | |
| 54 | n += 1; | |
| 55 | @"fn" += 1; | |
| 56 | r = x - @"fn" * pio2_1; | |
| 57 | w = @"fn" * pio2_1t; | |
| 58 | } | |
| 59 | y[0] = r - w; | |
| 60 | ui = @bitCast(u64, y[0]); | |
| 61 | ey = @intCast(i32, (ui >> 52) & 0x7ff); | |
| 62 | ex = @intCast(i32, ix >> 20); | |
| 63 | if (ex - ey > 16) { // 2nd round, good to 118 bits | |
| 64 | t = r; | |
| 65 | w = @"fn" * pio2_2; | |
| 66 | r = t - w; | |
| 67 | w = @"fn" * pio2_2t - ((t - r) - w); | |
| 68 | y[0] = r - w; | |
| 69 | ui = @bitCast(u64, y[0]); | |
| 70 | ey = @intCast(i32, (ui >> 52) & 0x7ff); | |
| 71 | if (ex - ey > 49) { // 3rd round, good to 151 bits, covers all cases | |
| 72 | t = r; | |
| 73 | w = @"fn" * pio2_3; | |
| 74 | r = t - w; | |
| 75 | w = @"fn" * pio2_3t - ((t - r) - w); | |
| 76 | y[0] = r - w; | |
| 77 | } | |
| 78 | } | |
| 79 | y[1] = (r - y[0]) - w; | |
| 80 | return n; | |
| 81 | } | |
| 82 | ||
| 83 | // Returns the remainder of x rem pi/2 in y[0]+y[1] | |
| 84 | // | |
| 85 | // use __rem_pio2_large() for large x | |
| 86 | // | |
| 87 | // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ | |
| 88 | pub fn __rem_pio2(x: f64, y: *[2]f64) i32 { | |
| 89 | var z: f64 = undefined; | |
| 90 | var tx: [3]f64 = undefined; | |
| 91 | var ty: [2]f64 = undefined; | |
| 92 | var n: i32 = undefined; | |
| 93 | var ix: u32 = undefined; | |
| 94 | var sign: bool = undefined; | |
| 95 | var i: i32 = undefined; | |
| 96 | var ui: u64 = undefined; | |
| 97 | ||
| 98 | ui = @bitCast(u64, x); | |
| 99 | sign = ui >> 63 != 0; | |
| 100 | ix = @truncate(u32, (ui >> 32) & 0x7fffffff); | |
| 101 | if (ix <= 0x400f6a7a) { // |x| ~<= 5pi/4 | |
| 102 | if ((ix & 0xfffff) == 0x921fb) { // |x| ~= pi/2 or 2pi/2 | |
| 103 | return medium(ix, x, y); | |
| 104 | } | |
| 105 | if (ix <= 0x4002d97c) { // |x| ~<= 3pi/4 | |
| 106 | if (!sign) { | |
| 107 | z = x - pio2_1; // one round good to 85 bits | |
| 108 | y[0] = z - pio2_1t; | |
| 109 | y[1] = (z - y[0]) - pio2_1t; | |
| 110 | return 1; | |
| 111 | } else { | |
| 112 | z = x + pio2_1; | |
| 113 | y[0] = z + pio2_1t; | |
| 114 | y[1] = (z - y[0]) + pio2_1t; | |
| 115 | return -1; | |
| 116 | } | |
| 117 | } else { | |
| 118 | if (!sign) { | |
| 119 | z = x - 2 * pio2_1; | |
| 120 | y[0] = z - 2 * pio2_1t; | |
| 121 | y[1] = (z - y[0]) - 2 * pio2_1t; | |
| 122 | return 2; | |
| 123 | } else { | |
| 124 | z = x + 2 * pio2_1; | |
| 125 | y[0] = z + 2 * pio2_1t; | |
| 126 | y[1] = (z - y[0]) + 2 * pio2_1t; | |
| 127 | return -2; | |
| 128 | } | |
| 129 | } | |
| 130 | } | |
| 131 | if (ix <= 0x401c463b) { // |x| ~<= 9pi/4 | |
| 132 | if (ix <= 0x4015fdbc) { // |x| ~<= 7pi/4 | |
| 133 | if (ix == 0x4012d97c) { // |x| ~= 3pi/2 | |
| 134 | return medium(ix, x, y); | |
| 135 | } | |
| 136 | if (!sign) { | |
| 137 | z = x - 3 * pio2_1; | |
| 138 | y[0] = z - 3 * pio2_1t; | |
| 139 | y[1] = (z - y[0]) - 3 * pio2_1t; | |
| 140 | return 3; | |
| 141 | } else { | |
| 142 | z = x + 3 * pio2_1; | |
| 143 | y[0] = z + 3 * pio2_1t; | |
| 144 | y[1] = (z - y[0]) + 3 * pio2_1t; | |
| 145 | return -3; | |
| 146 | } | |
| 147 | } else { | |
| 148 | if (ix == 0x401921fb) { // |x| ~= 4pi/2 */ | |
| 149 | return medium(ix, x, y); | |
| 150 | } | |
| 151 | if (!sign) { | |
| 152 | z = x - 4 * pio2_1; | |
| 153 | y[0] = z - 4 * pio2_1t; | |
| 154 | y[1] = (z - y[0]) - 4 * pio2_1t; | |
| 155 | return 4; | |
| 156 | } else { | |
| 157 | z = x + 4 * pio2_1; | |
| 158 | y[0] = z + 4 * pio2_1t; | |
| 159 | y[1] = (z - y[0]) + 4 * pio2_1t; | |
| 160 | return -4; | |
| 161 | } | |
| 162 | } | |
| 163 | } | |
| 164 | if (ix < 0x413921fb) { // |x| ~< 2^20*(pi/2), medium size | |
| 165 | return medium(ix, x, y); | |
| 166 | } | |
| 167 | // all other (large) arguments | |
| 168 | if (ix >= 0x7ff00000) { // x is inf or NaN | |
| 169 | y[0] = x - x; | |
| 170 | y[1] = y[0]; | |
| 171 | return 0; | |
| 172 | } | |
| 173 | // set z = scalbn(|x|,-ilogb(x)+23) | |
| 174 | ui = @bitCast(u64, x); | |
| 175 | ui &= std.math.maxInt(u64) >> 12; | |
| 176 | ui |= @as(u64, 0x3ff + 23) << 52; | |
| 177 | z = @bitCast(f64, ui); | |
| 178 | ||
| 179 | i = 0; | |
| 180 | while (i < 2) : (i += 1) { | |
| 181 | tx[U(i)] = @intToFloat(f64, @floatToInt(i32, z)); | |
| 182 | z = (z - tx[U(i)]) * 0x1p24; | |
| 183 | } | |
| 184 | tx[U(i)] = z; | |
| 185 | // skip zero terms, first term is non-zero | |
| 186 | while (tx[U(i)] == 0.0) { | |
| 187 | i -= 1; | |
| 188 | } | |
| 189 | n = __rem_pio2_large(tx[0..], ty[0..], @intCast(i32, (ix >> 20)) - (0x3ff + 23), i + 1, 1); | |
| 190 | if (sign) { | |
| 191 | y[0] = -ty[0]; | |
| 192 | y[1] = -ty[1]; | |
| 193 | return -n; | |
| 194 | } | |
| 195 | y[0] = ty[0]; | |
| 196 | y[1] = ty[1]; | |
| 197 | return n; | |
| 198 | } |
lib/std/math/__rem_pio2_large.zig deleted-510| ... | ... | @@ -1,510 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__rem_pio2_large.c | |
| 5 | ||
| 6 | const std = @import("../std.zig"); | |
| 7 | const math = std.math; | |
| 8 | ||
| 9 | const init_jk = [_]i32{ 3, 4, 4, 6 }; // initial value for jk | |
| 10 | ||
| 11 | // | |
| 12 | // Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi | |
| 13 | // | |
| 14 | // integer array, contains the (24*i)-th to (24*i+23)-th | |
| 15 | // bit of 2/pi after binary point. The corresponding | |
| 16 | // floating value is | |
| 17 | // | |
| 18 | // ipio2[i] * 2^(-24(i+1)). | |
| 19 | // | |
| 20 | // NB: This table must have at least (e0-3)/24 + jk terms. | |
| 21 | // For quad precision (e0 <= 16360, jk = 6), this is 686. | |
| 22 | /// | |
| 23 | const ipio2 = [_]i32{ | |
| 24 | 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, | |
| 25 | 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, | |
| 26 | 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, | |
| 27 | 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, | |
| 28 | 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, | |
| 29 | 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, | |
| 30 | 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, | |
| 31 | 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, | |
| 32 | 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, | |
| 33 | 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, | |
| 34 | 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, | |
| 35 | ||
| 36 | //#if LDBL_MAX_EXP > 1024 | |
| 37 | 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, | |
| 38 | 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, | |
| 39 | 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, | |
| 40 | 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, | |
| 41 | 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, | |
| 42 | 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, | |
| 43 | 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, | |
| 44 | 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, | |
| 45 | 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, | |
| 46 | 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, | |
| 47 | 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, | |
| 48 | 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, | |
| 49 | 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, | |
| 50 | 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, | |
| 51 | 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, | |
| 52 | 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, | |
| 53 | 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, | |
| 54 | 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, | |
| 55 | 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, | |
| 56 | 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, | |
| 57 | 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, | |
| 58 | 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, | |
| 59 | 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, | |
| 60 | 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, | |
| 61 | 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, | |
| 62 | 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, | |
| 63 | 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, | |
| 64 | 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, | |
| 65 | 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, | |
| 66 | 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, | |
| 67 | 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, | |
| 68 | 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, | |
| 69 | 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, | |
| 70 | 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, | |
| 71 | 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, | |
| 72 | 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, | |
| 73 | 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, | |
| 74 | 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, | |
| 75 | 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, | |
| 76 | 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, | |
| 77 | 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, | |
| 78 | 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, | |
| 79 | 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, | |
| 80 | 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, | |
| 81 | 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, | |
| 82 | 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, | |
| 83 | 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, | |
| 84 | 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, | |
| 85 | 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, | |
| 86 | 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, | |
| 87 | 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, | |
| 88 | 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, | |
| 89 | 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, | |
| 90 | 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, | |
| 91 | 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, | |
| 92 | 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, | |
| 93 | 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, | |
| 94 | 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, | |
| 95 | 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, | |
| 96 | 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, | |
| 97 | 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, | |
| 98 | 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, | |
| 99 | 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, | |
| 100 | 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, | |
| 101 | 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, | |
| 102 | 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, | |
| 103 | 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, | |
| 104 | 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, | |
| 105 | 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, | |
| 106 | 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, | |
| 107 | 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, | |
| 108 | 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, | |
| 109 | 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, | |
| 110 | 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, | |
| 111 | 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, | |
| 112 | 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, | |
| 113 | 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, | |
| 114 | 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, | |
| 115 | 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, | |
| 116 | 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, | |
| 117 | 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, | |
| 118 | 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, | |
| 119 | 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, | |
| 120 | 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, | |
| 121 | 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, | |
| 122 | 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, | |
| 123 | 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, | |
| 124 | 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, | |
| 125 | 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, | |
| 126 | 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, | |
| 127 | 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, | |
| 128 | 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, | |
| 129 | 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, | |
| 130 | 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, | |
| 131 | 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, | |
| 132 | 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, | |
| 133 | 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, | |
| 134 | 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, | |
| 135 | 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, | |
| 136 | 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, | |
| 137 | 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, | |
| 138 | 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, | |
| 139 | 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, | |
| 140 | 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, | |
| 141 | 0x8071E0, | |
| 142 | //#endif | |
| 143 | }; | |
| 144 | ||
| 145 | const PIo2 = [_]f64{ | |
| 146 | 1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000 | |
| 147 | 7.54978941586159635335e-08, // 0x3E74442D, 0x00000000 | |
| 148 | 5.39030252995776476554e-15, // 0x3CF84698, 0x80000000 | |
| 149 | 3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000 | |
| 150 | 1.27065575308067607349e-29, // 0x39F01B83, 0x80000000 | |
| 151 | 1.22933308981111328932e-36, // 0x387A2520, 0x40000000 | |
| 152 | 2.73370053816464559624e-44, // 0x36E38222, 0x80000000 | |
| 153 | 2.16741683877804819444e-51, // 0x3569F31D, 0x00000000 | |
| 154 | }; | |
| 155 | ||
| 156 | fn U(x: anytype) usize { | |
| 157 | return @intCast(usize, x); | |
| 158 | } | |
| 159 | ||
| 160 | // Returns the last three digits of N with y = x - N*pi/2 so that |y| < pi/2. | |
| 161 | // | |
| 162 | // The method is to compute the integer (mod 8) and fraction parts of | |
| 163 | // (2/pi)*x without doing the full multiplication. In general we | |
| 164 | // skip the part of the product that are known to be a huge integer ( | |
| 165 | // more accurately, = 0 mod 8 ). Thus the number of operations are | |
| 166 | // independent of the exponent of the input. | |
| 167 | // | |
| 168 | // (2/pi) is represented by an array of 24-bit integers in ipio2[]. | |
| 169 | // | |
| 170 | // Input parameters: | |
| 171 | // x[] The input value (must be positive) is broken into nx | |
| 172 | // pieces of 24-bit integers in double precision format. | |
| 173 | // x[i] will be the i-th 24 bit of x. The scaled exponent | |
| 174 | // of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 | |
| 175 | // match x's up to 24 bits. | |
| 176 | // | |
| 177 | // Example of breaking a double positive z into x[0]+x[1]+x[2]: | |
| 178 | // e0 = ilogb(z)-23 | |
| 179 | // z = scalbn(z,-e0) | |
| 180 | // for i = 0,1,2 | |
| 181 | // x[i] = floor(z) | |
| 182 | // z = (z-x[i])*2**24 | |
| 183 | // | |
| 184 | // | |
| 185 | // y[] ouput result in an array of double precision numbers. | |
| 186 | // The dimension of y[] is: | |
| 187 | // 24-bit precision 1 | |
| 188 | // 53-bit precision 2 | |
| 189 | // 64-bit precision 2 | |
| 190 | // 113-bit precision 3 | |
| 191 | // The actual value is the sum of them. Thus for 113-bit | |
| 192 | // precison, one may have to do something like: | |
| 193 | // | |
| 194 | // long double t,w,r_head, r_tail; | |
| 195 | // t = (long double)y[2] + (long double)y[1]; | |
| 196 | // w = (long double)y[0]; | |
| 197 | // r_head = t+w; | |
| 198 | // r_tail = w - (r_head - t); | |
| 199 | // | |
| 200 | // e0 The exponent of x[0]. Must be <= 16360 or you need to | |
| 201 | // expand the ipio2 table. | |
| 202 | // | |
| 203 | // nx dimension of x[] | |
| 204 | // | |
| 205 | // prec an integer indicating the precision: | |
| 206 | // 0 24 bits (single) | |
| 207 | // 1 53 bits (double) | |
| 208 | // 2 64 bits (extended) | |
| 209 | // 3 113 bits (quad) | |
| 210 | // | |
| 211 | // Here is the description of some local variables: | |
| 212 | // | |
| 213 | // jk jk+1 is the initial number of terms of ipio2[] needed | |
| 214 | // in the computation. The minimum and recommended value | |
| 215 | // for jk is 3,4,4,6 for single, double, extended, and quad. | |
| 216 | // jk+1 must be 2 larger than you might expect so that our | |
| 217 | // recomputation test works. (Up to 24 bits in the integer | |
| 218 | // part (the 24 bits of it that we compute) and 23 bits in | |
| 219 | // the fraction part may be lost to cancelation before we | |
| 220 | // recompute.) | |
| 221 | // | |
| 222 | // jz local integer variable indicating the number of | |
| 223 | // terms of ipio2[] used. | |
| 224 | // | |
| 225 | // jx nx - 1 | |
| 226 | // | |
| 227 | // jv index for pointing to the suitable ipio2[] for the | |
| 228 | // computation. In general, we want | |
| 229 | // ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 | |
| 230 | // is an integer. Thus | |
| 231 | // e0-3-24*jv >= 0 or (e0-3)/24 >= jv | |
| 232 | // Hence jv = max(0,(e0-3)/24). | |
| 233 | // | |
| 234 | // jp jp+1 is the number of terms in PIo2[] needed, jp = jk. | |
| 235 | // | |
| 236 | // q[] double array with integral value, representing the | |
| 237 | // 24-bits chunk of the product of x and 2/pi. | |
| 238 | // | |
| 239 | // q0 the corresponding exponent of q[0]. Note that the | |
| 240 | // exponent for q[i] would be q0-24*i. | |
| 241 | // | |
| 242 | // PIo2[] double precision array, obtained by cutting pi/2 | |
| 243 | // into 24 bits chunks. | |
| 244 | // | |
| 245 | // f[] ipio2[] in floating point | |
| 246 | // | |
| 247 | // iq[] integer array by breaking up q[] in 24-bits chunk. | |
| 248 | // | |
| 249 | // fq[] final product of x*(2/pi) in fq[0],..,fq[jk] | |
| 250 | // | |
| 251 | // ih integer. If >0 it indicates q[] is >= 0.5, hence | |
| 252 | // it also indicates the *sign* of the result. | |
| 253 | // | |
| 254 | /// | |
| 255 | // | |
| 256 | // Constants: | |
| 257 | // The hexadecimal values are the intended ones for the following | |
| 258 | // constants. The decimal values may be used, provided that the | |
| 259 | // compiler will convert from decimal to binary accurately enough | |
| 260 | // to produce the hexadecimal values shown. | |
| 261 | /// | |
| 262 | pub fn __rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 { | |
| 263 | var jz: i32 = undefined; | |
| 264 | var jx: i32 = undefined; | |
| 265 | var jv: i32 = undefined; | |
| 266 | var jp: i32 = undefined; | |
| 267 | var jk: i32 = undefined; | |
| 268 | var carry: i32 = undefined; | |
| 269 | var n: i32 = undefined; | |
| 270 | var iq: [20]i32 = undefined; | |
| 271 | var i: i32 = undefined; | |
| 272 | var j: i32 = undefined; | |
| 273 | var k: i32 = undefined; | |
| 274 | var m: i32 = undefined; | |
| 275 | var q0: i32 = undefined; | |
| 276 | var ih: i32 = undefined; | |
| 277 | ||
| 278 | var z: f64 = undefined; | |
| 279 | var fw: f64 = undefined; | |
| 280 | var f: [20]f64 = undefined; | |
| 281 | var fq: [20]f64 = undefined; | |
| 282 | var q: [20]f64 = undefined; | |
| 283 | ||
| 284 | // initialize jk | |
| 285 | jk = init_jk[prec]; | |
| 286 | jp = jk; | |
| 287 | ||
| 288 | // determine jx,jv,q0, note that 3>q0 | |
| 289 | jx = nx - 1; | |
| 290 | jv = @divFloor(e0 - 3, 24); | |
| 291 | if (jv < 0) jv = 0; | |
| 292 | q0 = e0 - 24 * (jv + 1); | |
| 293 | ||
| 294 | // set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] | |
| 295 | j = jv - jx; | |
| 296 | m = jx + jk; | |
| 297 | i = 0; | |
| 298 | while (i <= m) : ({ | |
| 299 | i += 1; | |
| 300 | j += 1; | |
| 301 | }) { | |
| 302 | f[U(i)] = if (j < 0) 0.0 else @intToFloat(f64, ipio2[U(j)]); | |
| 303 | } | |
| 304 | ||
| 305 | // compute q[0],q[1],...q[jk] | |
| 306 | i = 0; | |
| 307 | while (i <= jk) : (i += 1) { | |
| 308 | j = 0; | |
| 309 | fw = 0; | |
| 310 | while (j <= jx) : (j += 1) { | |
| 311 | fw += x[U(j)] * f[U(jx + i - j)]; | |
| 312 | } | |
| 313 | q[U(i)] = fw; | |
| 314 | } | |
| 315 | ||
| 316 | jz = jk; | |
| 317 | ||
| 318 | // This is to handle a non-trivial goto translation from C. | |
| 319 | // An unconditional return statement is found at the end of this loop. | |
| 320 | recompute: while (true) { | |
| 321 | // distill q[] into iq[] reversingly | |
| 322 | i = 0; | |
| 323 | j = jz; | |
| 324 | z = q[U(jz)]; | |
| 325 | while (j > 0) : ({ | |
| 326 | i += 1; | |
| 327 | j -= 1; | |
| 328 | }) { | |
| 329 | fw = @intToFloat(f64, @floatToInt(i32, 0x1p-24 * z)); | |
| 330 | iq[U(i)] = @floatToInt(i32, z - 0x1p24 * fw); | |
| 331 | z = q[U(j - 1)] + fw; | |
| 332 | } | |
| 333 | ||
| 334 | // compute n | |
| 335 | z = math.scalbn(z, q0); // actual value of z | |
| 336 | z -= 8.0 * math.floor(z * 0.125); // trim off integer >= 8 | |
| 337 | n = @floatToInt(i32, z); | |
| 338 | z -= @intToFloat(f64, n); | |
| 339 | ih = 0; | |
| 340 | if (q0 > 0) { // need iq[jz-1] to determine n | |
| 341 | i = iq[U(jz - 1)] >> @intCast(u5, 24 - q0); | |
| 342 | n += i; | |
| 343 | iq[U(jz - 1)] -= i << @intCast(u5, 24 - q0); | |
| 344 | ih = iq[U(jz - 1)] >> @intCast(u5, 23 - q0); | |
| 345 | } else if (q0 == 0) { | |
| 346 | ih = iq[U(jz - 1)] >> 23; | |
| 347 | } else if (z >= 0.5) { | |
| 348 | ih = 2; | |
| 349 | } | |
| 350 | ||
| 351 | if (ih > 0) { // q > 0.5 | |
| 352 | n += 1; | |
| 353 | carry = 0; | |
| 354 | i = 0; | |
| 355 | while (i < jz) : (i += 1) { // compute 1-q | |
| 356 | j = iq[U(i)]; | |
| 357 | if (carry == 0) { | |
| 358 | if (j != 0) { | |
| 359 | carry = 1; | |
| 360 | iq[U(i)] = 0x1000000 - j; | |
| 361 | } | |
| 362 | } else { | |
| 363 | iq[U(i)] = 0xffffff - j; | |
| 364 | } | |
| 365 | } | |
| 366 | if (q0 > 0) { // rare case: chance is 1 in 12 | |
| 367 | switch (q0) { | |
| 368 | 1 => iq[U(jz - 1)] &= 0x7fffff, | |
| 369 | 2 => iq[U(jz - 1)] &= 0x3fffff, | |
| 370 | else => unreachable, | |
| 371 | } | |
| 372 | } | |
| 373 | if (ih == 2) { | |
| 374 | z = 1.0 - z; | |
| 375 | if (carry != 0) { | |
| 376 | z -= math.scalbn(@as(f64, 1.0), q0); | |
| 377 | } | |
| 378 | } | |
| 379 | } | |
| 380 | ||
| 381 | // check if recomputation is needed | |
| 382 | if (z == 0.0) { | |
| 383 | j = 0; | |
| 384 | i = jz - 1; | |
| 385 | while (i >= jk) : (i -= 1) { | |
| 386 | j |= iq[U(i)]; | |
| 387 | } | |
| 388 | ||
| 389 | if (j == 0) { // need recomputation | |
| 390 | k = 1; | |
| 391 | while (iq[U(jk - k)] == 0) : (k += 1) { | |
| 392 | // k = no. of terms needed | |
| 393 | } | |
| 394 | ||
| 395 | i = jz + 1; | |
| 396 | while (i <= jz + k) : (i += 1) { // add q[jz+1] to q[jz+k] | |
| 397 | f[U(jx + i)] = @intToFloat(f64, ipio2[U(jv + i)]); | |
| 398 | j = 0; | |
| 399 | fw = 0; | |
| 400 | while (j <= jx) : (j += 1) { | |
| 401 | fw += x[U(j)] * f[U(jx + i - j)]; | |
| 402 | } | |
| 403 | q[U(i)] = fw; | |
| 404 | } | |
| 405 | jz += k; | |
| 406 | continue :recompute; // mimic goto recompute | |
| 407 | } | |
| 408 | } | |
| 409 | ||
| 410 | // chop off zero terms | |
| 411 | if (z == 0.0) { | |
| 412 | jz -= 1; | |
| 413 | q0 -= 24; | |
| 414 | while (iq[U(jz)] == 0) { | |
| 415 | jz -= 1; | |
| 416 | q0 -= 24; | |
| 417 | } | |
| 418 | } else { // break z into 24-bit if necessary | |
| 419 | z = math.scalbn(z, -q0); | |
| 420 | if (z >= 0x1p24) { | |
| 421 | fw = @intToFloat(f64, @floatToInt(i32, 0x1p-24 * z)); | |
| 422 | iq[U(jz)] = @floatToInt(i32, z - 0x1p24 * fw); | |
| 423 | jz += 1; | |
| 424 | q0 += 24; | |
| 425 | iq[U(jz)] = @floatToInt(i32, fw); | |
| 426 | } else { | |
| 427 | iq[U(jz)] = @floatToInt(i32, z); | |
| 428 | } | |
| 429 | } | |
| 430 | ||
| 431 | // convert integer "bit" chunk to floating-point value | |
| 432 | fw = math.scalbn(@as(f64, 1.0), q0); | |
| 433 | i = jz; | |
| 434 | while (i >= 0) : (i -= 1) { | |
| 435 | q[U(i)] = fw * @intToFloat(f64, iq[U(i)]); | |
| 436 | fw *= 0x1p-24; | |
| 437 | } | |
| 438 | ||
| 439 | // compute PIo2[0,...,jp]*q[jz,...,0] | |
| 440 | i = jz; | |
| 441 | while (i >= 0) : (i -= 1) { | |
| 442 | fw = 0; | |
| 443 | k = 0; | |
| 444 | while (k <= jp and k <= jz - i) : (k += 1) { | |
| 445 | fw += PIo2[U(k)] * q[U(i + k)]; | |
| 446 | } | |
| 447 | fq[U(jz - i)] = fw; | |
| 448 | } | |
| 449 | ||
| 450 | // compress fq[] into y[] | |
| 451 | switch (prec) { | |
| 452 | 0 => { | |
| 453 | fw = 0.0; | |
| 454 | i = jz; | |
| 455 | while (i >= 0) : (i -= 1) { | |
| 456 | fw += fq[U(i)]; | |
| 457 | } | |
| 458 | y[0] = if (ih == 0) fw else -fw; | |
| 459 | }, | |
| 460 | ||
| 461 | 1, 2 => { | |
| 462 | fw = 0.0; | |
| 463 | i = jz; | |
| 464 | while (i >= 0) : (i -= 1) { | |
| 465 | fw += fq[U(i)]; | |
| 466 | } | |
| 467 | // TODO: drop excess precision here once double_t is used | |
| 468 | fw = fw; | |
| 469 | y[0] = if (ih == 0) fw else -fw; | |
| 470 | fw = fq[0] - fw; | |
| 471 | i = 1; | |
| 472 | while (i <= jz) : (i += 1) { | |
| 473 | fw += fq[U(i)]; | |
| 474 | } | |
| 475 | y[1] = if (ih == 0) fw else -fw; | |
| 476 | }, | |
| 477 | 3 => { // painful | |
| 478 | i = jz; | |
| 479 | while (i > 0) : (i -= 1) { | |
| 480 | fw = fq[U(i - 1)] + fq[U(i)]; | |
| 481 | fq[U(i)] += fq[U(i - 1)] - fw; | |
| 482 | fq[U(i - 1)] = fw; | |
| 483 | } | |
| 484 | i = jz; | |
| 485 | while (i > 1) : (i -= 1) { | |
| 486 | fw = fq[U(i - 1)] + fq[U(i)]; | |
| 487 | fq[U(i)] += fq[U(i - 1)] - fw; | |
| 488 | fq[U(i - 1)] = fw; | |
| 489 | } | |
| 490 | fw = 0; | |
| 491 | i = jz; | |
| 492 | while (i >= 2) : (i -= 1) { | |
| 493 | fw += fq[U(i)]; | |
| 494 | } | |
| 495 | if (ih == 0) { | |
| 496 | y[0] = fq[0]; | |
| 497 | y[1] = fq[1]; | |
| 498 | y[2] = fw; | |
| 499 | } else { | |
| 500 | y[0] = -fq[0]; | |
| 501 | y[1] = -fq[1]; | |
| 502 | y[2] = -fw; | |
| 503 | } | |
| 504 | }, | |
| 505 | else => unreachable, | |
| 506 | } | |
| 507 | ||
| 508 | return n & 7; | |
| 509 | } | |
| 510 | } |
lib/std/math/__rem_pio2f.zig deleted-70| ... | ... | @@ -1,70 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__rem_pio2f.c | |
| 5 | ||
| 6 | const std = @import("../std.zig"); | |
| 7 | const __rem_pio2_large = @import("__rem_pio2_large.zig").__rem_pio2_large; | |
| 8 | const math = std.math; | |
| 9 | ||
| 10 | const toint = 1.5 / math.floatEps(f64); | |
| 11 | // pi/4 | |
| 12 | const pio4 = 0x1.921fb6p-1; | |
| 13 | // invpio2: 53 bits of 2/pi | |
| 14 | const invpio2 = 6.36619772367581382433e-01; // 0x3FE45F30, 0x6DC9C883 | |
| 15 | // pio2_1: first 25 bits of pi/2 | |
| 16 | const pio2_1 = 1.57079631090164184570e+00; // 0x3FF921FB, 0x50000000 | |
| 17 | // pio2_1t: pi/2 - pio2_1 | |
| 18 | const pio2_1t = 1.58932547735281966916e-08; // 0x3E5110b4, 0x611A6263 | |
| 19 | ||
| 20 | // Returns the remainder of x rem pi/2 in *y | |
| 21 | // use double precision for everything except passing x | |
| 22 | // use __rem_pio2_large() for large x | |
| 23 | pub fn __rem_pio2f(x: f32, y: *f64) i32 { | |
| 24 | var tx: [1]f64 = undefined; | |
| 25 | var ty: [1]f64 = undefined; | |
| 26 | var @"fn": f64 = undefined; | |
| 27 | var ix: u32 = undefined; | |
| 28 | var n: i32 = undefined; | |
| 29 | var sign: bool = undefined; | |
| 30 | var e0: u32 = undefined; | |
| 31 | var ui: u32 = undefined; | |
| 32 | ||
| 33 | ui = @bitCast(u32, x); | |
| 34 | ix = ui & 0x7fffffff; | |
| 35 | ||
| 36 | // 25+53 bit pi is good enough for medium size | |
| 37 | if (ix < 0x4dc90fdb) { // |x| ~< 2^28*(pi/2), medium size | |
| 38 | // Use a specialized rint() to get fn. | |
| 39 | @"fn" = @floatCast(f64, x) * invpio2 + toint - toint; | |
| 40 | n = @floatToInt(i32, @"fn"); | |
| 41 | y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t; | |
| 42 | // Matters with directed rounding. | |
| 43 | if (y.* < -pio4) { | |
| 44 | n -= 1; | |
| 45 | @"fn" -= 1; | |
| 46 | y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t; | |
| 47 | } else if (y.* > pio4) { | |
| 48 | n += 1; | |
| 49 | @"fn" += 1; | |
| 50 | y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t; | |
| 51 | } | |
| 52 | return n; | |
| 53 | } | |
| 54 | if (ix >= 0x7f800000) { // x is inf or NaN | |
| 55 | y.* = x - x; | |
| 56 | return 0; | |
| 57 | } | |
| 58 | // scale x into [2^23, 2^24-1] | |
| 59 | sign = ui >> 31 != 0; | |
| 60 | e0 = (ix >> 23) - (0x7f + 23); // e0 = ilogb(|x|)-23, positive | |
| 61 | ui = ix - (e0 << 23); | |
| 62 | tx[0] = @bitCast(f32, ui); | |
| 63 | n = __rem_pio2_large(&tx, &ty, @intCast(i32, e0), 1, 0); | |
| 64 | if (sign) { | |
| 65 | y.* = -ty[0]; | |
| 66 | return -n; | |
| 67 | } | |
| 68 | y.* = ty[0]; | |
| 69 | return n; | |
| 70 | } |
lib/std/math/__trig.zig deleted-273| ... | ... | @@ -1,273 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__cos.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__cosdf.c | |
| 6 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__sin.c | |
| 7 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__sindf.c | |
| 8 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__tand.c | |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__tandf.c | |
| 10 | ||
| 11 | // kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 | |
| 12 | // Input x is assumed to be bounded by ~pi/4 in magnitude. | |
| 13 | // Input y is the tail of x. | |
| 14 | // | |
| 15 | // Algorithm | |
| 16 | // 1. Since cos(-x) = cos(x), we need only to consider positive x. | |
| 17 | // 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. | |
| 18 | // 3. cos(x) is approximated by a polynomial of degree 14 on | |
| 19 | // [0,pi/4] | |
| 20 | // 4 14 | |
| 21 | // cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x | |
| 22 | // where the remez error is | |
| 23 | // | |
| 24 | // | 2 4 6 8 10 12 14 | -58 | |
| 25 | // |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 | |
| 26 | // | | | |
| 27 | // | |
| 28 | // 4 6 8 10 12 14 | |
| 29 | // 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then | |
| 30 | // cos(x) ~ 1 - x*x/2 + r | |
| 31 | // since cos(x+y) ~ cos(x) - sin(x)*y | |
| 32 | // ~ cos(x) - x*y, | |
| 33 | // a correction term is necessary in cos(x) and hence | |
| 34 | // cos(x+y) = 1 - (x*x/2 - (r - x*y)) | |
| 35 | // For better accuracy, rearrange to | |
| 36 | // cos(x+y) ~ w + (tmp + (r-x*y)) | |
| 37 | // where w = 1 - x*x/2 and tmp is a tiny correction term | |
| 38 | // (1 - x*x/2 == w + tmp exactly in infinite precision). | |
| 39 | // The exactness of w + tmp in infinite precision depends on w | |
| 40 | // and tmp having the same precision as x. If they have extra | |
| 41 | // precision due to compiler bugs, then the extra precision is | |
| 42 | // only good provided it is retained in all terms of the final | |
| 43 | // expression for cos(). Retention happens in all cases tested | |
| 44 | // under FreeBSD, so don't pessimize things by forcibly clipping | |
| 45 | // any extra precision in w. | |
| 46 | pub fn __cos(x: f64, y: f64) f64 { | |
| 47 | const C1 = 4.16666666666666019037e-02; // 0x3FA55555, 0x5555554C | |
| 48 | const C2 = -1.38888888888741095749e-03; // 0xBF56C16C, 0x16C15177 | |
| 49 | const C3 = 2.48015872894767294178e-05; // 0x3EFA01A0, 0x19CB1590 | |
| 50 | const C4 = -2.75573143513906633035e-07; // 0xBE927E4F, 0x809C52AD | |
| 51 | const C5 = 2.08757232129817482790e-09; // 0x3E21EE9E, 0xBDB4B1C4 | |
| 52 | const C6 = -1.13596475577881948265e-11; // 0xBDA8FAE9, 0xBE8838D4 | |
| 53 | ||
| 54 | const z = x * x; | |
| 55 | const zs = z * z; | |
| 56 | const r = z * (C1 + z * (C2 + z * C3)) + zs * zs * (C4 + z * (C5 + z * C6)); | |
| 57 | const hz = 0.5 * z; | |
| 58 | const w = 1.0 - hz; | |
| 59 | return w + (((1.0 - w) - hz) + (z * r - x * y)); | |
| 60 | } | |
| 61 | ||
| 62 | pub fn __cosdf(x: f64) f32 { | |
| 63 | // |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). | |
| 64 | const C0 = -0x1ffffffd0c5e81.0p-54; // -0.499999997251031003120 | |
| 65 | const C1 = 0x155553e1053a42.0p-57; // 0.0416666233237390631894 | |
| 66 | const C2 = -0x16c087e80f1e27.0p-62; // -0.00138867637746099294692 | |
| 67 | const C3 = 0x199342e0ee5069.0p-68; // 0.0000243904487962774090654 | |
| 68 | ||
| 69 | // Try to optimize for parallel evaluation as in __tandf.c. | |
| 70 | const z = x * x; | |
| 71 | const w = z * z; | |
| 72 | const r = C2 + z * C3; | |
| 73 | return @floatCast(f32, ((1.0 + z * C0) + w * C1) + (w * z) * r); | |
| 74 | } | |
| 75 | ||
| 76 | // kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 | |
| 77 | // Input x is assumed to be bounded by ~pi/4 in magnitude. | |
| 78 | // Input y is the tail of x. | |
| 79 | // Input iy indicates whether y is 0. (if iy=0, y assume to be 0). | |
| 80 | // | |
| 81 | // Algorithm | |
| 82 | // 1. Since sin(-x) = -sin(x), we need only to consider positive x. | |
| 83 | // 2. Callers must return sin(-0) = -0 without calling here since our | |
| 84 | // odd polynomial is not evaluated in a way that preserves -0. | |
| 85 | // Callers may do the optimization sin(x) ~ x for tiny x. | |
| 86 | // 3. sin(x) is approximated by a polynomial of degree 13 on | |
| 87 | // [0,pi/4] | |
| 88 | // 3 13 | |
| 89 | // sin(x) ~ x + S1*x + ... + S6*x | |
| 90 | // where | |
| 91 | // | |
| 92 | // |sin(x) 2 4 6 8 10 12 | -58 | |
| 93 | // |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 | |
| 94 | // | x | | |
| 95 | // | |
| 96 | // 4. sin(x+y) = sin(x) + sin'(x')*y | |
| 97 | // ~ sin(x) + (1-x*x/2)*y | |
| 98 | // For better accuracy, let | |
| 99 | // 3 2 2 2 2 | |
| 100 | // r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) | |
| 101 | // then 3 2 | |
| 102 | // sin(x) = x + (S1*x + (x *(r-y/2)+y)) | |
| 103 | pub fn __sin(x: f64, y: f64, iy: i32) f64 { | |
| 104 | const S1 = -1.66666666666666324348e-01; // 0xBFC55555, 0x55555549 | |
| 105 | const S2 = 8.33333333332248946124e-03; // 0x3F811111, 0x1110F8A6 | |
| 106 | const S3 = -1.98412698298579493134e-04; // 0xBF2A01A0, 0x19C161D5 | |
| 107 | const S4 = 2.75573137070700676789e-06; // 0x3EC71DE3, 0x57B1FE7D | |
| 108 | const S5 = -2.50507602534068634195e-08; // 0xBE5AE5E6, 0x8A2B9CEB | |
| 109 | const S6 = 1.58969099521155010221e-10; // 0x3DE5D93A, 0x5ACFD57C | |
| 110 | ||
| 111 | const z = x * x; | |
| 112 | const w = z * z; | |
| 113 | const r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); | |
| 114 | const v = z * x; | |
| 115 | if (iy == 0) { | |
| 116 | return x + v * (S1 + z * r); | |
| 117 | } else { | |
| 118 | return x - ((z * (0.5 * y - v * r) - y) - v * S1); | |
| 119 | } | |
| 120 | } | |
| 121 | ||
| 122 | pub fn __sindf(x: f64) f32 { | |
| 123 | // |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). | |
| 124 | const S1 = -0x15555554cbac77.0p-55; // -0.166666666416265235595 | |
| 125 | const S2 = 0x111110896efbb2.0p-59; // 0.0083333293858894631756 | |
| 126 | const S3 = -0x1a00f9e2cae774.0p-65; // -0.000198393348360966317347 | |
| 127 | const S4 = 0x16cd878c3b46a7.0p-71; // 0.0000027183114939898219064 | |
| 128 | ||
| 129 | // Try to optimize for parallel evaluation as in __tandf.c. | |
| 130 | const z = x * x; | |
| 131 | const w = z * z; | |
| 132 | const r = S3 + z * S4; | |
| 133 | const s = z * x; | |
| 134 | return @floatCast(f32, (x + s * (S1 + z * S2)) + s * w * r); | |
| 135 | } | |
| 136 | ||
| 137 | // kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 | |
| 138 | // Input x is assumed to be bounded by ~pi/4 in magnitude. | |
| 139 | // Input y is the tail of x. | |
| 140 | // Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. | |
| 141 | // | |
| 142 | // Algorithm | |
| 143 | // 1. Since tan(-x) = -tan(x), we need only to consider positive x. | |
| 144 | // 2. Callers must return tan(-0) = -0 without calling here since our | |
| 145 | // odd polynomial is not evaluated in a way that preserves -0. | |
| 146 | // Callers may do the optimization tan(x) ~ x for tiny x. | |
| 147 | // 3. tan(x) is approximated by a odd polynomial of degree 27 on | |
| 148 | // [0,0.67434] | |
| 149 | // 3 27 | |
| 150 | // tan(x) ~ x + T1*x + ... + T13*x | |
| 151 | // where | |
| 152 | // | |
| 153 | // |tan(x) 2 4 26 | -59.2 | |
| 154 | // |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 | |
| 155 | // | x | | |
| 156 | // | |
| 157 | // Note: tan(x+y) = tan(x) + tan'(x)*y | |
| 158 | // ~ tan(x) + (1+x*x)*y | |
| 159 | // Therefore, for better accuracy in computing tan(x+y), let | |
| 160 | // 3 2 2 2 2 | |
| 161 | // r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) | |
| 162 | // then | |
| 163 | // 3 2 | |
| 164 | // tan(x+y) = x + (T1*x + (x *(r+y)+y)) | |
| 165 | // | |
| 166 | // 4. For x in [0.67434,pi/4], let y = pi/4 - x, then | |
| 167 | // tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) | |
| 168 | // = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) | |
| 169 | pub fn __tan(x_: f64, y_: f64, odd: bool) f64 { | |
| 170 | var x = x_; | |
| 171 | var y = y_; | |
| 172 | ||
| 173 | const T = [_]f64{ | |
| 174 | 3.33333333333334091986e-01, // 3FD55555, 55555563 | |
| 175 | 1.33333333333201242699e-01, // 3FC11111, 1110FE7A | |
| 176 | 5.39682539762260521377e-02, // 3FABA1BA, 1BB341FE | |
| 177 | 2.18694882948595424599e-02, // 3F9664F4, 8406D637 | |
| 178 | 8.86323982359930005737e-03, // 3F8226E3, E96E8493 | |
| 179 | 3.59207910759131235356e-03, // 3F6D6D22, C9560328 | |
| 180 | 1.45620945432529025516e-03, // 3F57DBC8, FEE08315 | |
| 181 | 5.88041240820264096874e-04, // 3F4344D8, F2F26501 | |
| 182 | 2.46463134818469906812e-04, // 3F3026F7, 1A8D1068 | |
| 183 | 7.81794442939557092300e-05, // 3F147E88, A03792A6 | |
| 184 | 7.14072491382608190305e-05, // 3F12B80F, 32F0A7E9 | |
| 185 | -1.85586374855275456654e-05, // BEF375CB, DB605373 | |
| 186 | 2.59073051863633712884e-05, // 3EFB2A70, 74BF7AD4 | |
| 187 | }; | |
| 188 | const pio4 = 7.85398163397448278999e-01; // 3FE921FB, 54442D18 | |
| 189 | const pio4lo = 3.06161699786838301793e-17; // 3C81A626, 33145C07 | |
| 190 | ||
| 191 | var z: f64 = undefined; | |
| 192 | var r: f64 = undefined; | |
| 193 | var v: f64 = undefined; | |
| 194 | var w: f64 = undefined; | |
| 195 | var s: f64 = undefined; | |
| 196 | var a: f64 = undefined; | |
| 197 | var w0: f64 = undefined; | |
| 198 | var a0: f64 = undefined; | |
| 199 | var hx: u32 = undefined; | |
| 200 | var sign: bool = undefined; | |
| 201 | ||
| 202 | hx = @intCast(u32, @bitCast(u64, x) >> 32); | |
| 203 | const big = (hx & 0x7fffffff) >= 0x3FE59428; // |x| >= 0.6744 | |
| 204 | if (big) { | |
| 205 | sign = hx >> 31 != 0; | |
| 206 | if (sign) { | |
| 207 | x = -x; | |
| 208 | y = -y; | |
| 209 | } | |
| 210 | x = (pio4 - x) + (pio4lo - y); | |
| 211 | y = 0.0; | |
| 212 | } | |
| 213 | z = x * x; | |
| 214 | w = z * z; | |
| 215 | ||
| 216 | // Break x^5*(T[1]+x^2*T[2]+...) into | |
| 217 | // x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + | |
| 218 | // x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) | |
| 219 | r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); | |
| 220 | v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); | |
| 221 | s = z * x; | |
| 222 | r = y + z * (s * (r + v) + y) + s * T[0]; | |
| 223 | w = x + r; | |
| 224 | if (big) { | |
| 225 | s = 1 - 2 * @intToFloat(f64, @boolToInt(odd)); | |
| 226 | v = s - 2.0 * (x + (r - w * w / (w + s))); | |
| 227 | return if (sign) -v else v; | |
| 228 | } | |
| 229 | if (!odd) { | |
| 230 | return w; | |
| 231 | } | |
| 232 | // -1.0/(x+r) has up to 2ulp error, so compute it accurately | |
| 233 | w0 = w; | |
| 234 | w0 = @bitCast(f64, @bitCast(u64, w0) & 0xffffffff00000000); | |
| 235 | v = r - (w0 - x); // w0+v = r+x | |
| 236 | a = -1.0 / w; | |
| 237 | a0 = a; | |
| 238 | a0 = @bitCast(f64, @bitCast(u64, a0) & 0xffffffff00000000); | |
| 239 | return a0 + a * (1.0 + a0 * w0 + a0 * v); | |
| 240 | } | |
| 241 | ||
| 242 | pub fn __tandf(x: f64, odd: bool) f32 { | |
| 243 | // |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). | |
| 244 | const T = [_]f64{ | |
| 245 | 0x15554d3418c99f.0p-54, // 0.333331395030791399758 | |
| 246 | 0x1112fd38999f72.0p-55, // 0.133392002712976742718 | |
| 247 | 0x1b54c91d865afe.0p-57, // 0.0533812378445670393523 | |
| 248 | 0x191df3908c33ce.0p-58, // 0.0245283181166547278873 | |
| 249 | 0x185dadfcecf44e.0p-61, // 0.00297435743359967304927 | |
| 250 | 0x1362b9bf971bcd.0p-59, // 0.00946564784943673166728 | |
| 251 | }; | |
| 252 | ||
| 253 | const z = x * x; | |
| 254 | // Split up the polynomial into small independent terms to give | |
| 255 | // opportunities for parallel evaluation. The chosen splitting is | |
| 256 | // micro-optimized for Athlons (XP, X64). It costs 2 multiplications | |
| 257 | // relative to Horner's method on sequential machines. | |
| 258 | // | |
| 259 | // We add the small terms from lowest degree up for efficiency on | |
| 260 | // non-sequential machines (the lowest degree terms tend to be ready | |
| 261 | // earlier). Apart from this, we don't care about order of | |
| 262 | // operations, and don't need to to care since we have precision to | |
| 263 | // spare. However, the chosen splitting is good for accuracy too, | |
| 264 | // and would give results as accurate as Horner's method if the | |
| 265 | // small terms were added from highest degree down. | |
| 266 | const r = T[4] + z * T[5]; | |
| 267 | const t = T[2] + z * T[3]; | |
| 268 | const w = z * z; | |
| 269 | const s = z * x; | |
| 270 | const u = T[0] + z * T[1]; | |
| 271 | const r0 = (x + s * u) + (s * w) * (t + w * r); | |
| 272 | return @floatCast(f32, if (odd) -1.0 / r0 else r0); | |
| 273 | } |
lib/std/math/acos.zig+4-4| ... | ... | @@ -64,14 +64,14 @@ fn acos32(x: f32) f32 { |
| 64 | 64 | // x < -0.5 |
| 65 | 65 | if (hx >> 31 != 0) { |
| 66 | 66 | const z = (1 + x) * 0.5; |
| 67 | const s = math.sqrt(z); | |
| 67 | const s = @sqrt(z); | |
| 68 | 68 | const w = r32(z) * s - pio2_lo; |
| 69 | 69 | return 2 * (pio2_hi - (s + w)); |
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | // x > 0.5 |
| 73 | 73 | const z = (1.0 - x) * 0.5; |
| 74 | const s = math.sqrt(z); | |
| 74 | const s = @sqrt(z); | |
| 75 | 75 | const jx = @bitCast(u32, s); |
| 76 | 76 | const df = @bitCast(f32, jx & 0xFFFFF000); |
| 77 | 77 | const c = (z - df * df) / (s + df); |
| ... | ... | @@ -133,14 +133,14 @@ fn acos64(x: f64) f64 { |
| 133 | 133 | // x < -0.5 |
| 134 | 134 | if (hx >> 31 != 0) { |
| 135 | 135 | const z = (1.0 + x) * 0.5; |
| 136 | const s = math.sqrt(z); | |
| 136 | const s = @sqrt(z); | |
| 137 | 137 | const w = r64(z) * s - pio2_lo; |
| 138 | 138 | return 2 * (pio2_hi - (s + w)); |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | 141 | // x > 0.5 |
| 142 | 142 | const z = (1.0 - x) * 0.5; |
| 143 | const s = math.sqrt(z); | |
| 143 | const s = @sqrt(z); | |
| 144 | 144 | const jx = @bitCast(u64, s); |
| 145 | 145 | const df = @bitCast(f64, jx & 0xFFFFFFFF00000000); |
| 146 | 146 | const c = (z - df * df) / (s + df); |
lib/std/math/acosh.zig+6-6| ... | ... | @@ -29,15 +29,15 @@ fn acosh32(x: f32) f32 { |
| 29 | 29 | |
| 30 | 30 | // |x| < 2, invalid if x < 1 or nan |
| 31 | 31 | if (i < 0x3F800000 + (1 << 23)) { |
| 32 | return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1))); | |
| 32 | return math.log1p(x - 1 + @sqrt((x - 1) * (x - 1) + 2 * (x - 1))); | |
| 33 | 33 | } |
| 34 | 34 | // |x| < 0x1p12 |
| 35 | 35 | else if (i < 0x3F800000 + (12 << 23)) { |
| 36 | return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1))); | |
| 36 | return @log(2 * x - 1 / (x + @sqrt(x * x - 1))); | |
| 37 | 37 | } |
| 38 | 38 | // |x| >= 0x1p12 |
| 39 | 39 | else { |
| 40 | return math.ln(x) + 0.693147180559945309417232121458176568; | |
| 40 | return @log(x) + 0.693147180559945309417232121458176568; | |
| 41 | 41 | } |
| 42 | 42 | } |
| 43 | 43 | |
| ... | ... | @@ -47,15 +47,15 @@ fn acosh64(x: f64) f64 { |
| 47 | 47 | |
| 48 | 48 | // |x| < 2, invalid if x < 1 or nan |
| 49 | 49 | if (e < 0x3FF + 1) { |
| 50 | return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1))); | |
| 50 | return math.log1p(x - 1 + @sqrt((x - 1) * (x - 1) + 2 * (x - 1))); | |
| 51 | 51 | } |
| 52 | 52 | // |x| < 0x1p26 |
| 53 | 53 | else if (e < 0x3FF + 26) { |
| 54 | return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1))); | |
| 54 | return @log(2 * x - 1 / (x + @sqrt(x * x - 1))); | |
| 55 | 55 | } |
| 56 | 56 | // |x| >= 0x1p26 or nan |
| 57 | 57 | else { |
| 58 | return math.ln(x) + 0.693147180559945309417232121458176568; | |
| 58 | return @log(x) + 0.693147180559945309417232121458176568; | |
| 59 | 59 | } |
| 60 | 60 | } |
| 61 | 61 |
lib/std/math/asin.zig+4-4| ... | ... | @@ -60,8 +60,8 @@ fn asin32(x: f32) f32 { |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | // 1 > |x| >= 0.5 |
| 63 | const z = (1 - math.fabs(x)) * 0.5; | |
| 64 | const s = math.sqrt(z); | |
| 63 | const z = (1 - @fabs(x)) * 0.5; | |
| 64 | const s = @sqrt(z); | |
| 65 | 65 | const fx = pio2 - 2 * (s + s * r32(z)); |
| 66 | 66 | |
| 67 | 67 | if (hx >> 31 != 0) { |
| ... | ... | @@ -119,8 +119,8 @@ fn asin64(x: f64) f64 { |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | 121 | // 1 > |x| >= 0.5 |
| 122 | const z = (1 - math.fabs(x)) * 0.5; | |
| 123 | const s = math.sqrt(z); | |
| 122 | const z = (1 - @fabs(x)) * 0.5; | |
| 123 | const s = @sqrt(z); | |
| 124 | 124 | const r = r64(z); |
| 125 | 125 | var fx: f64 = undefined; |
| 126 | 126 |
lib/std/math/asinh.zig+6-6| ... | ... | @@ -39,15 +39,15 @@ fn asinh32(x: f32) f32 { |
| 39 | 39 | |
| 40 | 40 | // |x| >= 0x1p12 or inf or nan |
| 41 | 41 | if (i >= 0x3F800000 + (12 << 23)) { |
| 42 | rx = math.ln(rx) + 0.69314718055994530941723212145817656; | |
| 42 | rx = @log(rx) + 0.69314718055994530941723212145817656; | |
| 43 | 43 | } |
| 44 | 44 | // |x| >= 2 |
| 45 | 45 | else if (i >= 0x3F800000 + (1 << 23)) { |
| 46 | rx = math.ln(2 * x + 1 / (math.sqrt(x * x + 1) + x)); | |
| 46 | rx = @log(2 * x + 1 / (@sqrt(x * x + 1) + x)); | |
| 47 | 47 | } |
| 48 | 48 | // |x| >= 0x1p-12, up to 1.6ulp error |
| 49 | 49 | else if (i >= 0x3F800000 - (12 << 23)) { |
| 50 | rx = math.log1p(x + x * x / (math.sqrt(x * x + 1) + 1)); | |
| 50 | rx = math.log1p(x + x * x / (@sqrt(x * x + 1) + 1)); | |
| 51 | 51 | } |
| 52 | 52 | // |x| < 0x1p-12, inexact if x != 0 |
| 53 | 53 | else { |
| ... | ... | @@ -70,15 +70,15 @@ fn asinh64(x: f64) f64 { |
| 70 | 70 | |
| 71 | 71 | // |x| >= 0x1p26 or inf or nan |
| 72 | 72 | if (e >= 0x3FF + 26) { |
| 73 | rx = math.ln(rx) + 0.693147180559945309417232121458176568; | |
| 73 | rx = @log(rx) + 0.693147180559945309417232121458176568; | |
| 74 | 74 | } |
| 75 | 75 | // |x| >= 2 |
| 76 | 76 | else if (e >= 0x3FF + 1) { |
| 77 | rx = math.ln(2 * x + 1 / (math.sqrt(x * x + 1) + x)); | |
| 77 | rx = @log(2 * x + 1 / (@sqrt(x * x + 1) + x)); | |
| 78 | 78 | } |
| 79 | 79 | // |x| >= 0x1p-12, up to 1.6ulp error |
| 80 | 80 | else if (e >= 0x3FF - 26) { |
| 81 | rx = math.log1p(x + x * x / (math.sqrt(x * x + 1) + 1)); | |
| 81 | rx = math.log1p(x + x * x / (@sqrt(x * x + 1) + 1)); | |
| 82 | 82 | } |
| 83 | 83 | // |x| < 0x1p-12, inexact if x != 0 |
| 84 | 84 | else { |
lib/std/math/atan.zig+2-2| ... | ... | @@ -73,7 +73,7 @@ fn atan32(x_: f32) f32 { |
| 73 | 73 | } |
| 74 | 74 | id = null; |
| 75 | 75 | } else { |
| 76 | x = math.fabs(x); | |
| 76 | x = @fabs(x); | |
| 77 | 77 | // |x| < 1.1875 |
| 78 | 78 | if (ix < 0x3F980000) { |
| 79 | 79 | // 7/16 <= |x| < 11/16 |
| ... | ... | @@ -171,7 +171,7 @@ fn atan64(x_: f64) f64 { |
| 171 | 171 | } |
| 172 | 172 | id = null; |
| 173 | 173 | } else { |
| 174 | x = math.fabs(x); | |
| 174 | x = @fabs(x); | |
| 175 | 175 | // |x| < 1.1875 |
| 176 | 176 | if (ix < 0x3FF30000) { |
| 177 | 177 | // 7/16 <= |x| < 11/16 |
lib/std/math/atan2.zig+2-2| ... | ... | @@ -108,7 +108,7 @@ fn atan2_32(y: f32, x: f32) f32 { |
| 108 | 108 | if ((m & 2) != 0 and iy + (26 << 23) < ix) { |
| 109 | 109 | break :z 0.0; |
| 110 | 110 | } else { |
| 111 | break :z math.atan(math.fabs(y / x)); | |
| 111 | break :z math.atan(@fabs(y / x)); | |
| 112 | 112 | } |
| 113 | 113 | }; |
| 114 | 114 | |
| ... | ... | @@ -198,7 +198,7 @@ fn atan2_64(y: f64, x: f64) f64 { |
| 198 | 198 | if ((m & 2) != 0 and iy +% (64 << 20) < ix) { |
| 199 | 199 | break :z 0.0; |
| 200 | 200 | } else { |
| 201 | break :z math.atan(math.fabs(y / x)); | |
| 201 | break :z math.atan(@fabs(y / x)); | |
| 202 | 202 | } |
| 203 | 203 | }; |
| 204 | 204 |
lib/std/math/ceil.zig deleted-170| ... | ... | @@ -1,170 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c | |
| 6 | ||
| 7 | const std = @import("../std.zig"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | /// Returns the least integer value greater than of equal to x. | |
| 12 | /// | |
| 13 | /// Special Cases: | |
| 14 | /// - ceil(+-0) = +-0 | |
| 15 | /// - ceil(+-inf) = +-inf | |
| 16 | /// - ceil(nan) = nan | |
| 17 | pub fn ceil(x: anytype) @TypeOf(x) { | |
| 18 | const T = @TypeOf(x); | |
| 19 | return switch (T) { | |
| 20 | f32 => ceil32(x), | |
| 21 | f64 => ceil64(x), | |
| 22 | f128 => ceil128(x), | |
| 23 | ||
| 24 | // TODO this is not correct for some targets | |
| 25 | c_longdouble => @floatCast(c_longdouble, ceil128(x)), | |
| 26 | ||
| 27 | else => @compileError("ceil not implemented for " ++ @typeName(T)), | |
| 28 | }; | |
| 29 | } | |
| 30 | ||
| 31 | fn ceil32(x: f32) f32 { | |
| 32 | var u = @bitCast(u32, x); | |
| 33 | var e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F; | |
| 34 | var m: u32 = undefined; | |
| 35 | ||
| 36 | // TODO: Shouldn't need this explicit check. | |
| 37 | if (x == 0.0) { | |
| 38 | return x; | |
| 39 | } | |
| 40 | ||
| 41 | if (e >= 23) { | |
| 42 | return x; | |
| 43 | } else if (e >= 0) { | |
| 44 | m = @as(u32, 0x007FFFFF) >> @intCast(u5, e); | |
| 45 | if (u & m == 0) { | |
| 46 | return x; | |
| 47 | } | |
| 48 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 49 | if (u >> 31 == 0) { | |
| 50 | u += m; | |
| 51 | } | |
| 52 | u &= ~m; | |
| 53 | return @bitCast(f32, u); | |
| 54 | } else { | |
| 55 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 56 | if (u >> 31 != 0) { | |
| 57 | return -0.0; | |
| 58 | } else { | |
| 59 | return 1.0; | |
| 60 | } | |
| 61 | } | |
| 62 | } | |
| 63 | ||
| 64 | fn ceil64(x: f64) f64 { | |
| 65 | const f64_toint = 1.0 / math.floatEps(f64); | |
| 66 | ||
| 67 | const u = @bitCast(u64, x); | |
| 68 | const e = (u >> 52) & 0x7FF; | |
| 69 | var y: f64 = undefined; | |
| 70 | ||
| 71 | if (e >= 0x3FF + 52 or x == 0) { | |
| 72 | return x; | |
| 73 | } | |
| 74 | ||
| 75 | if (u >> 63 != 0) { | |
| 76 | y = x - f64_toint + f64_toint - x; | |
| 77 | } else { | |
| 78 | y = x + f64_toint - f64_toint - x; | |
| 79 | } | |
| 80 | ||
| 81 | if (e <= 0x3FF - 1) { | |
| 82 | math.doNotOptimizeAway(y); | |
| 83 | if (u >> 63 != 0) { | |
| 84 | return -0.0; | |
| 85 | } else { | |
| 86 | return 1.0; | |
| 87 | } | |
| 88 | } else if (y < 0) { | |
| 89 | return x + y + 1; | |
| 90 | } else { | |
| 91 | return x + y; | |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | fn ceil128(x: f128) f128 { | |
| 96 | const f128_toint = 1.0 / math.floatEps(f128); | |
| 97 | ||
| 98 | const u = @bitCast(u128, x); | |
| 99 | const e = (u >> 112) & 0x7FFF; | |
| 100 | var y: f128 = undefined; | |
| 101 | ||
| 102 | if (e >= 0x3FFF + 112 or x == 0) return x; | |
| 103 | ||
| 104 | if (u >> 127 != 0) { | |
| 105 | y = x - f128_toint + f128_toint - x; | |
| 106 | } else { | |
| 107 | y = x + f128_toint - f128_toint - x; | |
| 108 | } | |
| 109 | ||
| 110 | if (e <= 0x3FFF - 1) { | |
| 111 | math.doNotOptimizeAway(y); | |
| 112 | if (u >> 127 != 0) { | |
| 113 | return -0.0; | |
| 114 | } else { | |
| 115 | return 1.0; | |
| 116 | } | |
| 117 | } else if (y < 0) { | |
| 118 | return x + y + 1; | |
| 119 | } else { | |
| 120 | return x + y; | |
| 121 | } | |
| 122 | } | |
| 123 | ||
| 124 | test "math.ceil" { | |
| 125 | try expect(ceil(@as(f32, 0.0)) == ceil32(0.0)); | |
| 126 | try expect(ceil(@as(f64, 0.0)) == ceil64(0.0)); | |
| 127 | try expect(ceil(@as(f128, 0.0)) == ceil128(0.0)); | |
| 128 | } | |
| 129 | ||
| 130 | test "math.ceil32" { | |
| 131 | try expect(ceil32(1.3) == 2.0); | |
| 132 | try expect(ceil32(-1.3) == -1.0); | |
| 133 | try expect(ceil32(0.2) == 1.0); | |
| 134 | } | |
| 135 | ||
| 136 | test "math.ceil64" { | |
| 137 | try expect(ceil64(1.3) == 2.0); | |
| 138 | try expect(ceil64(-1.3) == -1.0); | |
| 139 | try expect(ceil64(0.2) == 1.0); | |
| 140 | } | |
| 141 | ||
| 142 | test "math.ceil128" { | |
| 143 | try expect(ceil128(1.3) == 2.0); | |
| 144 | try expect(ceil128(-1.3) == -1.0); | |
| 145 | try expect(ceil128(0.2) == 1.0); | |
| 146 | } | |
| 147 | ||
| 148 | test "math.ceil32.special" { | |
| 149 | try expect(ceil32(0.0) == 0.0); | |
| 150 | try expect(ceil32(-0.0) == -0.0); | |
| 151 | try expect(math.isPositiveInf(ceil32(math.inf(f32)))); | |
| 152 | try expect(math.isNegativeInf(ceil32(-math.inf(f32)))); | |
| 153 | try expect(math.isNan(ceil32(math.nan(f32)))); | |
| 154 | } | |
| 155 | ||
| 156 | test "math.ceil64.special" { | |
| 157 | try expect(ceil64(0.0) == 0.0); | |
| 158 | try expect(ceil64(-0.0) == -0.0); | |
| 159 | try expect(math.isPositiveInf(ceil64(math.inf(f64)))); | |
| 160 | try expect(math.isNegativeInf(ceil64(-math.inf(f64)))); | |
| 161 | try expect(math.isNan(ceil64(math.nan(f64)))); | |
| 162 | } | |
| 163 | ||
| 164 | test "math.ceil128.special" { | |
| 165 | try expect(ceil128(0.0) == 0.0); | |
| 166 | try expect(ceil128(-0.0) == -0.0); | |
| 167 | try expect(math.isPositiveInf(ceil128(math.inf(f128)))); | |
| 168 | try expect(math.isNegativeInf(ceil128(-math.inf(f128)))); | |
| 169 | try expect(math.isNan(ceil128(math.nan(f128)))); | |
| 170 | } |
lib/std/math/complex.zig+1-1| ... | ... | @@ -115,7 +115,7 @@ pub fn Complex(comptime T: type) type { |
| 115 | 115 | |
| 116 | 116 | /// Returns the magnitude of a complex number. |
| 117 | 117 | pub fn magnitude(self: Self) T { |
| 118 | return math.sqrt(self.re * self.re + self.im * self.im); | |
| 118 | return @sqrt(self.re * self.re + self.im * self.im); | |
| 119 | 119 | } |
| 120 | 120 | }; |
| 121 | 121 | } |
lib/std/math/complex/atan.zig+2-2| ... | ... | @@ -66,7 +66,7 @@ fn atan32(z: Complex(f32)) Complex(f32) { |
| 66 | 66 | |
| 67 | 67 | t = y + 1.0; |
| 68 | 68 | a = (x2 + (t * t)) / a; |
| 69 | return Complex(f32).init(w, 0.25 * math.ln(a)); | |
| 69 | return Complex(f32).init(w, 0.25 * @log(a)); | |
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | fn redupif64(x: f64) f64 { |
| ... | ... | @@ -115,7 +115,7 @@ fn atan64(z: Complex(f64)) Complex(f64) { |
| 115 | 115 | |
| 116 | 116 | t = y + 1.0; |
| 117 | 117 | a = (x2 + (t * t)) / a; |
| 118 | return Complex(f64).init(w, 0.25 * math.ln(a)); | |
| 118 | return Complex(f64).init(w, 0.25 * @log(a)); | |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | 121 | const epsilon = 0.0001; |
lib/std/math/complex/cosh.zig+4-4| ... | ... | @@ -44,12 +44,12 @@ fn cosh32(z: Complex(f32)) Complex(f32) { |
| 44 | 44 | // |x|>= 9, so cosh(x) ~= exp(|x|) |
| 45 | 45 | if (ix < 0x42b17218) { |
| 46 | 46 | // x < 88.7: exp(|x|) won't overflow |
| 47 | const h = math.exp(math.fabs(x)) * 0.5; | |
| 47 | const h = @exp(@fabs(x)) * 0.5; | |
| 48 | 48 | return Complex(f32).init(math.copysign(f32, h, x) * math.cos(y), h * math.sin(y)); |
| 49 | 49 | } |
| 50 | 50 | // x < 192.7: scale to avoid overflow |
| 51 | 51 | else if (ix < 0x4340b1e7) { |
| 52 | const v = Complex(f32).init(math.fabs(x), y); | |
| 52 | const v = Complex(f32).init(@fabs(x), y); | |
| 53 | 53 | const r = ldexp_cexp(v, -1); |
| 54 | 54 | return Complex(f32).init(r.re, r.im * math.copysign(f32, 1, x)); |
| 55 | 55 | } |
| ... | ... | @@ -112,12 +112,12 @@ fn cosh64(z: Complex(f64)) Complex(f64) { |
| 112 | 112 | // |x|>= 22, so cosh(x) ~= exp(|x|) |
| 113 | 113 | if (ix < 0x40862e42) { |
| 114 | 114 | // x < 710: exp(|x|) won't overflow |
| 115 | const h = math.exp(math.fabs(x)) * 0.5; | |
| 115 | const h = @exp(@fabs(x)) * 0.5; | |
| 116 | 116 | return Complex(f64).init(h * math.cos(y), math.copysign(f64, h, x) * math.sin(y)); |
| 117 | 117 | } |
| 118 | 118 | // x < 1455: scale to avoid overflow |
| 119 | 119 | else if (ix < 0x4096bbaa) { |
| 120 | const v = Complex(f64).init(math.fabs(x), y); | |
| 120 | const v = Complex(f64).init(@fabs(x), y); | |
| 121 | 121 | const r = ldexp_cexp(v, -1); |
| 122 | 122 | return Complex(f64).init(r.re, r.im * math.copysign(f64, 1, x)); |
| 123 | 123 | } |
lib/std/math/complex/exp.zig+6-6| ... | ... | @@ -33,7 +33,7 @@ fn exp32(z: Complex(f32)) Complex(f32) { |
| 33 | 33 | const hy = @bitCast(u32, y) & 0x7fffffff; |
| 34 | 34 | // cexp(x + i0) = exp(x) + i0 |
| 35 | 35 | if (hy == 0) { |
| 36 | return Complex(f32).init(math.exp(x), y); | |
| 36 | return Complex(f32).init(@exp(x), y); | |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | const hx = @bitCast(u32, x); |
| ... | ... | @@ -63,7 +63,7 @@ fn exp32(z: Complex(f32)) Complex(f32) { |
| 63 | 63 | // - x = +-inf |
| 64 | 64 | // - x = nan |
| 65 | 65 | else { |
| 66 | const exp_x = math.exp(x); | |
| 66 | const exp_x = @exp(x); | |
| 67 | 67 | return Complex(f32).init(exp_x * math.cos(y), exp_x * math.sin(y)); |
| 68 | 68 | } |
| 69 | 69 | } |
| ... | ... | @@ -81,7 +81,7 @@ fn exp64(z: Complex(f64)) Complex(f64) { |
| 81 | 81 | |
| 82 | 82 | // cexp(x + i0) = exp(x) + i0 |
| 83 | 83 | if (hy | ly == 0) { |
| 84 | return Complex(f64).init(math.exp(x), y); | |
| 84 | return Complex(f64).init(@exp(x), y); | |
| 85 | 85 | } |
| 86 | 86 | |
| 87 | 87 | const fx = @bitCast(u64, x); |
| ... | ... | @@ -114,13 +114,13 @@ fn exp64(z: Complex(f64)) Complex(f64) { |
| 114 | 114 | // - x = +-inf |
| 115 | 115 | // - x = nan |
| 116 | 116 | else { |
| 117 | const exp_x = math.exp(x); | |
| 117 | const exp_x = @exp(x); | |
| 118 | 118 | return Complex(f64).init(exp_x * math.cos(y), exp_x * math.sin(y)); |
| 119 | 119 | } |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | 122 | test "complex.cexp32" { |
| 123 | const tolerance_f32 = math.sqrt(math.floatEps(f32)); | |
| 123 | const tolerance_f32 = @sqrt(math.floatEps(f32)); | |
| 124 | 124 | |
| 125 | 125 | { |
| 126 | 126 | const a = Complex(f32).init(5, 3); |
| ... | ... | @@ -140,7 +140,7 @@ test "complex.cexp32" { |
| 140 | 140 | } |
| 141 | 141 | |
| 142 | 142 | test "complex.cexp64" { |
| 143 | const tolerance_f64 = math.sqrt(math.floatEps(f64)); | |
| 143 | const tolerance_f64 = @sqrt(math.floatEps(f64)); | |
| 144 | 144 | |
| 145 | 145 | { |
| 146 | 146 | const a = Complex(f64).init(5, 3); |
lib/std/math/complex/ldexp.zig+2-2| ... | ... | @@ -26,7 +26,7 @@ fn frexp_exp32(x: f32, expt: *i32) f32 { |
| 26 | 26 | const k = 235; // reduction constant |
| 27 | 27 | const kln2 = 162.88958740; // k * ln2 |
| 28 | 28 | |
| 29 | const exp_x = math.exp(x - kln2); | |
| 29 | const exp_x = @exp(x - kln2); | |
| 30 | 30 | const hx = @bitCast(u32, exp_x); |
| 31 | 31 | // TODO zig should allow this cast implicitly because it should know the value is in range |
| 32 | 32 | expt.* = @intCast(i32, hx >> 23) - (0x7f + 127) + k; |
| ... | ... | @@ -54,7 +54,7 @@ fn frexp_exp64(x: f64, expt: *i32) f64 { |
| 54 | 54 | const k = 1799; // reduction constant |
| 55 | 55 | const kln2 = 1246.97177782734161156; // k * ln2 |
| 56 | 56 | |
| 57 | const exp_x = math.exp(x - kln2); | |
| 57 | const exp_x = @exp(x - kln2); | |
| 58 | 58 | |
| 59 | 59 | const fx = @bitCast(u64, exp_x); |
| 60 | 60 | const hx = @intCast(u32, fx >> 32); |
lib/std/math/complex/log.zig+1-1| ... | ... | @@ -10,7 +10,7 @@ pub fn log(z: anytype) Complex(@TypeOf(z.re)) { |
| 10 | 10 | const r = cmath.abs(z); |
| 11 | 11 | const phi = cmath.arg(z); |
| 12 | 12 | |
| 13 | return Complex(T).init(math.ln(r), phi); | |
| 13 | return Complex(T).init(@log(r), phi); | |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | 16 | const epsilon = 0.0001; |
lib/std/math/complex/sinh.zig+4-4| ... | ... | @@ -44,12 +44,12 @@ fn sinh32(z: Complex(f32)) Complex(f32) { |
| 44 | 44 | // |x|>= 9, so cosh(x) ~= exp(|x|) |
| 45 | 45 | if (ix < 0x42b17218) { |
| 46 | 46 | // x < 88.7: exp(|x|) won't overflow |
| 47 | const h = math.exp(math.fabs(x)) * 0.5; | |
| 47 | const h = @exp(@fabs(x)) * 0.5; | |
| 48 | 48 | return Complex(f32).init(math.copysign(f32, h, x) * math.cos(y), h * math.sin(y)); |
| 49 | 49 | } |
| 50 | 50 | // x < 192.7: scale to avoid overflow |
| 51 | 51 | else if (ix < 0x4340b1e7) { |
| 52 | const v = Complex(f32).init(math.fabs(x), y); | |
| 52 | const v = Complex(f32).init(@fabs(x), y); | |
| 53 | 53 | const r = ldexp_cexp(v, -1); |
| 54 | 54 | return Complex(f32).init(r.re * math.copysign(f32, 1, x), r.im); |
| 55 | 55 | } |
| ... | ... | @@ -111,12 +111,12 @@ fn sinh64(z: Complex(f64)) Complex(f64) { |
| 111 | 111 | // |x|>= 22, so cosh(x) ~= exp(|x|) |
| 112 | 112 | if (ix < 0x40862e42) { |
| 113 | 113 | // x < 710: exp(|x|) won't overflow |
| 114 | const h = math.exp(math.fabs(x)) * 0.5; | |
| 114 | const h = @exp(@fabs(x)) * 0.5; | |
| 115 | 115 | return Complex(f64).init(math.copysign(f64, h, x) * math.cos(y), h * math.sin(y)); |
| 116 | 116 | } |
| 117 | 117 | // x < 1455: scale to avoid overflow |
| 118 | 118 | else if (ix < 0x4096bbaa) { |
| 119 | const v = Complex(f64).init(math.fabs(x), y); | |
| 119 | const v = Complex(f64).init(@fabs(x), y); | |
| 120 | 120 | const r = ldexp_cexp(v, -1); |
| 121 | 121 | return Complex(f64).init(r.re * math.copysign(f64, 1, x), r.im); |
| 122 | 122 | } |
lib/std/math/complex/sqrt.zig+9-9| ... | ... | @@ -43,7 +43,7 @@ fn sqrt32(z: Complex(f32)) Complex(f32) { |
| 43 | 43 | // sqrt(-inf + i nan) = nan +- inf i |
| 44 | 44 | // sqrt(-inf + iy) = 0 + inf i |
| 45 | 45 | if (math.signbit(x)) { |
| 46 | return Complex(f32).init(math.fabs(x - y), math.copysign(f32, x, y)); | |
| 46 | return Complex(f32).init(@fabs(x - y), math.copysign(f32, x, y)); | |
| 47 | 47 | } else { |
| 48 | 48 | return Complex(f32).init(x, math.copysign(f32, y - y, y)); |
| 49 | 49 | } |
| ... | ... | @@ -56,15 +56,15 @@ fn sqrt32(z: Complex(f32)) Complex(f32) { |
| 56 | 56 | const dy = @as(f64, y); |
| 57 | 57 | |
| 58 | 58 | if (dx >= 0) { |
| 59 | const t = math.sqrt((dx + math.hypot(f64, dx, dy)) * 0.5); | |
| 59 | const t = @sqrt((dx + math.hypot(f64, dx, dy)) * 0.5); | |
| 60 | 60 | return Complex(f32).init( |
| 61 | 61 | @floatCast(f32, t), |
| 62 | 62 | @floatCast(f32, dy / (2.0 * t)), |
| 63 | 63 | ); |
| 64 | 64 | } else { |
| 65 | const t = math.sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5); | |
| 65 | const t = @sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5); | |
| 66 | 66 | return Complex(f32).init( |
| 67 | @floatCast(f32, math.fabs(y) / (2.0 * t)), | |
| 67 | @floatCast(f32, @fabs(y) / (2.0 * t)), | |
| 68 | 68 | @floatCast(f32, math.copysign(f64, t, y)), |
| 69 | 69 | ); |
| 70 | 70 | } |
| ... | ... | @@ -94,7 +94,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) { |
| 94 | 94 | // sqrt(-inf + i nan) = nan +- inf i |
| 95 | 95 | // sqrt(-inf + iy) = 0 + inf i |
| 96 | 96 | if (math.signbit(x)) { |
| 97 | return Complex(f64).init(math.fabs(x - y), math.copysign(f64, x, y)); | |
| 97 | return Complex(f64).init(@fabs(x - y), math.copysign(f64, x, y)); | |
| 98 | 98 | } else { |
| 99 | 99 | return Complex(f64).init(x, math.copysign(f64, y - y, y)); |
| 100 | 100 | } |
| ... | ... | @@ -104,7 +104,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) { |
| 104 | 104 | |
| 105 | 105 | // scale to avoid overflow |
| 106 | 106 | var scale = false; |
| 107 | if (math.fabs(x) >= threshold or math.fabs(y) >= threshold) { | |
| 107 | if (@fabs(x) >= threshold or @fabs(y) >= threshold) { | |
| 108 | 108 | x *= 0.25; |
| 109 | 109 | y *= 0.25; |
| 110 | 110 | scale = true; |
| ... | ... | @@ -112,11 +112,11 @@ fn sqrt64(z: Complex(f64)) Complex(f64) { |
| 112 | 112 | |
| 113 | 113 | var result: Complex(f64) = undefined; |
| 114 | 114 | if (x >= 0) { |
| 115 | const t = math.sqrt((x + math.hypot(f64, x, y)) * 0.5); | |
| 115 | const t = @sqrt((x + math.hypot(f64, x, y)) * 0.5); | |
| 116 | 116 | result = Complex(f64).init(t, y / (2.0 * t)); |
| 117 | 117 | } else { |
| 118 | const t = math.sqrt((-x + math.hypot(f64, x, y)) * 0.5); | |
| 119 | result = Complex(f64).init(math.fabs(y) / (2.0 * t), math.copysign(f64, t, y)); | |
| 118 | const t = @sqrt((-x + math.hypot(f64, x, y)) * 0.5); | |
| 119 | result = Complex(f64).init(@fabs(y) / (2.0 * t), math.copysign(f64, t, y)); | |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | 122 | if (scale) { |
lib/std/math/complex/tanh.zig+4-4| ... | ... | @@ -44,7 +44,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) { |
| 44 | 44 | |
| 45 | 45 | // x >= 11 |
| 46 | 46 | if (ix >= 0x41300000) { |
| 47 | const exp_mx = math.exp(-math.fabs(x)); | |
| 47 | const exp_mx = @exp(-@fabs(x)); | |
| 48 | 48 | return Complex(f32).init(math.copysign(f32, 1, x), 4 * math.sin(y) * math.cos(y) * exp_mx * exp_mx); |
| 49 | 49 | } |
| 50 | 50 | |
| ... | ... | @@ -52,7 +52,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) { |
| 52 | 52 | const t = math.tan(y); |
| 53 | 53 | const beta = 1.0 + t * t; |
| 54 | 54 | const s = math.sinh(x); |
| 55 | const rho = math.sqrt(1 + s * s); | |
| 55 | const rho = @sqrt(1 + s * s); | |
| 56 | 56 | const den = 1 + beta * s * s; |
| 57 | 57 | |
| 58 | 58 | return Complex(f32).init((beta * rho * s) / den, t / den); |
| ... | ... | @@ -87,7 +87,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) { |
| 87 | 87 | |
| 88 | 88 | // x >= 22 |
| 89 | 89 | if (ix >= 0x40360000) { |
| 90 | const exp_mx = math.exp(-math.fabs(x)); | |
| 90 | const exp_mx = @exp(-@fabs(x)); | |
| 91 | 91 | return Complex(f64).init(math.copysign(f64, 1, x), 4 * math.sin(y) * math.cos(y) * exp_mx * exp_mx); |
| 92 | 92 | } |
| 93 | 93 | |
| ... | ... | @@ -95,7 +95,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) { |
| 95 | 95 | const t = math.tan(y); |
| 96 | 96 | const beta = 1.0 + t * t; |
| 97 | 97 | const s = math.sinh(x); |
| 98 | const rho = math.sqrt(1 + s * s); | |
| 98 | const rho = @sqrt(1 + s * s); | |
| 99 | 99 | const den = 1 + beta * s * s; |
| 100 | 100 | |
| 101 | 101 | return Complex(f64).init((beta * rho * s) / den, t / den); |
lib/std/math/cos.zig deleted-154| ... | ... | @@ -1,154 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/cosf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/cos.c | |
| 6 | ||
| 7 | const std = @import("../std.zig"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | const kernel = @import("__trig.zig"); | |
| 12 | const __rem_pio2 = @import("__rem_pio2.zig").__rem_pio2; | |
| 13 | const __rem_pio2f = @import("__rem_pio2f.zig").__rem_pio2f; | |
| 14 | ||
| 15 | /// Returns the cosine of the radian value x. | |
| 16 | /// | |
| 17 | /// Special Cases: | |
| 18 | /// - cos(+-inf) = nan | |
| 19 | /// - cos(nan) = nan | |
| 20 | pub fn cos(x: anytype) @TypeOf(x) { | |
| 21 | const T = @TypeOf(x); | |
| 22 | return switch (T) { | |
| 23 | f32 => cos32(x), | |
| 24 | f64 => cos64(x), | |
| 25 | else => @compileError("cos not implemented for " ++ @typeName(T)), | |
| 26 | }; | |
| 27 | } | |
| 28 | ||
| 29 | fn cos32(x: f32) f32 { | |
| 30 | // Small multiples of pi/2 rounded to double precision. | |
| 31 | const c1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 | |
| 32 | const c2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 | |
| 33 | const c3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2 | |
| 34 | const c4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18 | |
| 35 | ||
| 36 | var ix = @bitCast(u32, x); | |
| 37 | const sign = ix >> 31 != 0; | |
| 38 | ix &= 0x7fffffff; | |
| 39 | ||
| 40 | if (ix <= 0x3f490fda) { // |x| ~<= pi/4 | |
| 41 | if (ix < 0x39800000) { // |x| < 2**-12 | |
| 42 | // raise inexact if x != 0 | |
| 43 | math.doNotOptimizeAway(x + 0x1p120); | |
| 44 | return 1.0; | |
| 45 | } | |
| 46 | return kernel.__cosdf(x); | |
| 47 | } | |
| 48 | if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4 | |
| 49 | if (ix > 0x4016cbe3) { // |x| ~> 3*pi/4 | |
| 50 | return -kernel.__cosdf(if (sign) x + c2pio2 else x - c2pio2); | |
| 51 | } else { | |
| 52 | if (sign) { | |
| 53 | return kernel.__sindf(x + c1pio2); | |
| 54 | } else { | |
| 55 | return kernel.__sindf(c1pio2 - x); | |
| 56 | } | |
| 57 | } | |
| 58 | } | |
| 59 | if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4 | |
| 60 | if (ix > 0x40afeddf) { // |x| ~> 7*pi/4 | |
| 61 | return kernel.__cosdf(if (sign) x + c4pio2 else x - c4pio2); | |
| 62 | } else { | |
| 63 | if (sign) { | |
| 64 | return kernel.__sindf(-x - c3pio2); | |
| 65 | } else { | |
| 66 | return kernel.__sindf(x - c3pio2); | |
| 67 | } | |
| 68 | } | |
| 69 | } | |
| 70 | ||
| 71 | // cos(Inf or NaN) is NaN | |
| 72 | if (ix >= 0x7f800000) { | |
| 73 | return x - x; | |
| 74 | } | |
| 75 | ||
| 76 | var y: f64 = undefined; | |
| 77 | const n = __rem_pio2f(x, &y); | |
| 78 | return switch (n & 3) { | |
| 79 | 0 => kernel.__cosdf(y), | |
| 80 | 1 => kernel.__sindf(-y), | |
| 81 | 2 => -kernel.__cosdf(y), | |
| 82 | else => kernel.__sindf(y), | |
| 83 | }; | |
| 84 | } | |
| 85 | ||
| 86 | fn cos64(x: f64) f64 { | |
| 87 | var ix = @bitCast(u64, x) >> 32; | |
| 88 | ix &= 0x7fffffff; | |
| 89 | ||
| 90 | // |x| ~< pi/4 | |
| 91 | if (ix <= 0x3fe921fb) { | |
| 92 | if (ix < 0x3e46a09e) { // |x| < 2**-27 * sqrt(2) | |
| 93 | // raise inexact if x!=0 | |
| 94 | math.doNotOptimizeAway(x + 0x1p120); | |
| 95 | return 1.0; | |
| 96 | } | |
| 97 | return kernel.__cos(x, 0); | |
| 98 | } | |
| 99 | ||
| 100 | // cos(Inf or NaN) is NaN | |
| 101 | if (ix >= 0x7ff00000) { | |
| 102 | return x - x; | |
| 103 | } | |
| 104 | ||
| 105 | var y: [2]f64 = undefined; | |
| 106 | const n = __rem_pio2(x, &y); | |
| 107 | return switch (n & 3) { | |
| 108 | 0 => kernel.__cos(y[0], y[1]), | |
| 109 | 1 => -kernel.__sin(y[0], y[1], 1), | |
| 110 | 2 => -kernel.__cos(y[0], y[1]), | |
| 111 | else => kernel.__sin(y[0], y[1], 1), | |
| 112 | }; | |
| 113 | } | |
| 114 | ||
| 115 | test "math.cos" { | |
| 116 | try expect(cos(@as(f32, 0.0)) == cos32(0.0)); | |
| 117 | try expect(cos(@as(f64, 0.0)) == cos64(0.0)); | |
| 118 | } | |
| 119 | ||
| 120 | test "math.cos32" { | |
| 121 | const epsilon = 0.00001; | |
| 122 | ||
| 123 | try expect(math.approxEqAbs(f32, cos32(0.0), 1.0, epsilon)); | |
| 124 | try expect(math.approxEqAbs(f32, cos32(0.2), 0.980067, epsilon)); | |
| 125 | try expect(math.approxEqAbs(f32, cos32(0.8923), 0.627623, epsilon)); | |
| 126 | try expect(math.approxEqAbs(f32, cos32(1.5), 0.070737, epsilon)); | |
| 127 | try expect(math.approxEqAbs(f32, cos32(-1.5), 0.070737, epsilon)); | |
| 128 | try expect(math.approxEqAbs(f32, cos32(37.45), 0.969132, epsilon)); | |
| 129 | try expect(math.approxEqAbs(f32, cos32(89.123), 0.400798, epsilon)); | |
| 130 | } | |
| 131 | ||
| 132 | test "math.cos64" { | |
| 133 | const epsilon = 0.000001; | |
| 134 | ||
| 135 | try expect(math.approxEqAbs(f64, cos64(0.0), 1.0, epsilon)); | |
| 136 | try expect(math.approxEqAbs(f64, cos64(0.2), 0.980067, epsilon)); | |
| 137 | try expect(math.approxEqAbs(f64, cos64(0.8923), 0.627623, epsilon)); | |
| 138 | try expect(math.approxEqAbs(f64, cos64(1.5), 0.070737, epsilon)); | |
| 139 | try expect(math.approxEqAbs(f64, cos64(-1.5), 0.070737, epsilon)); | |
| 140 | try expect(math.approxEqAbs(f64, cos64(37.45), 0.969132, epsilon)); | |
| 141 | try expect(math.approxEqAbs(f64, cos64(89.123), 0.40080, epsilon)); | |
| 142 | } | |
| 143 | ||
| 144 | test "math.cos32.special" { | |
| 145 | try expect(math.isNan(cos32(math.inf(f32)))); | |
| 146 | try expect(math.isNan(cos32(-math.inf(f32)))); | |
| 147 | try expect(math.isNan(cos32(math.nan(f32)))); | |
| 148 | } | |
| 149 | ||
| 150 | test "math.cos64.special" { | |
| 151 | try expect(math.isNan(cos64(math.inf(f64)))); | |
| 152 | try expect(math.isNan(cos64(-math.inf(f64)))); | |
| 153 | try expect(math.isNan(cos64(math.nan(f64)))); | |
| 154 | } |
lib/std/math/cosh.zig+2-2| ... | ... | @@ -45,7 +45,7 @@ fn cosh32(x: f32) f32 { |
| 45 | 45 | |
| 46 | 46 | // |x| < log(FLT_MAX) |
| 47 | 47 | if (ux < 0x42B17217) { |
| 48 | const t = math.exp(ax); | |
| 48 | const t = @exp(ax); | |
| 49 | 49 | return 0.5 * (t + 1 / t); |
| 50 | 50 | } |
| 51 | 51 | |
| ... | ... | @@ -77,7 +77,7 @@ fn cosh64(x: f64) f64 { |
| 77 | 77 | |
| 78 | 78 | // |x| < log(DBL_MAX) |
| 79 | 79 | if (w < 0x40862E42) { |
| 80 | const t = math.exp(ax); | |
| 80 | const t = @exp(ax); | |
| 81 | 81 | // NOTE: If x > log(0x1p26) then 1/t is not required. |
| 82 | 82 | return 0.5 * (t + 1 / t); |
| 83 | 83 | } |
lib/std/math/exp.zig deleted-217| ... | ... | @@ -1,217 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/expf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/exp.c | |
| 6 | ||
| 7 | const std = @import("../std.zig"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | /// Returns e raised to the power of x (e^x). | |
| 12 | /// | |
| 13 | /// Special Cases: | |
| 14 | /// - exp(+inf) = +inf | |
| 15 | /// - exp(nan) = nan | |
| 16 | pub fn exp(x: anytype) @TypeOf(x) { | |
| 17 | const T = @TypeOf(x); | |
| 18 | return switch (T) { | |
| 19 | f32 => exp32(x), | |
| 20 | f64 => exp64(x), | |
| 21 | else => @compileError("exp not implemented for " ++ @typeName(T)), | |
| 22 | }; | |
| 23 | } | |
| 24 | ||
| 25 | fn exp32(x_: f32) f32 { | |
| 26 | const half = [_]f32{ 0.5, -0.5 }; | |
| 27 | const ln2hi = 6.9314575195e-1; | |
| 28 | const ln2lo = 1.4286067653e-6; | |
| 29 | const invln2 = 1.4426950216e+0; | |
| 30 | const P1 = 1.6666625440e-1; | |
| 31 | const P2 = -2.7667332906e-3; | |
| 32 | ||
| 33 | var x = x_; | |
| 34 | var hx = @bitCast(u32, x); | |
| 35 | const sign = @intCast(i32, hx >> 31); | |
| 36 | hx &= 0x7FFFFFFF; | |
| 37 | ||
| 38 | if (math.isNan(x)) { | |
| 39 | return x; | |
| 40 | } | |
| 41 | ||
| 42 | // |x| >= -87.33655 or nan | |
| 43 | if (hx >= 0x42AEAC50) { | |
| 44 | // nan | |
| 45 | if (hx > 0x7F800000) { | |
| 46 | return x; | |
| 47 | } | |
| 48 | // x >= 88.722839 | |
| 49 | if (hx >= 0x42b17218 and sign == 0) { | |
| 50 | return x * 0x1.0p127; | |
| 51 | } | |
| 52 | if (sign != 0) { | |
| 53 | math.doNotOptimizeAway(-0x1.0p-149 / x); // overflow | |
| 54 | // x <= -103.972084 | |
| 55 | if (hx >= 0x42CFF1B5) { | |
| 56 | return 0; | |
| 57 | } | |
| 58 | } | |
| 59 | } | |
| 60 | ||
| 61 | var k: i32 = undefined; | |
| 62 | var hi: f32 = undefined; | |
| 63 | var lo: f32 = undefined; | |
| 64 | ||
| 65 | // |x| > 0.5 * ln2 | |
| 66 | if (hx > 0x3EB17218) { | |
| 67 | // |x| > 1.5 * ln2 | |
| 68 | if (hx > 0x3F851592) { | |
| 69 | k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]); | |
| 70 | } else { | |
| 71 | k = 1 - sign - sign; | |
| 72 | } | |
| 73 | ||
| 74 | const fk = @intToFloat(f32, k); | |
| 75 | hi = x - fk * ln2hi; | |
| 76 | lo = fk * ln2lo; | |
| 77 | x = hi - lo; | |
| 78 | } | |
| 79 | // |x| > 2^(-14) | |
| 80 | else if (hx > 0x39000000) { | |
| 81 | k = 0; | |
| 82 | hi = x; | |
| 83 | lo = 0; | |
| 84 | } else { | |
| 85 | math.doNotOptimizeAway(0x1.0p127 + x); // inexact | |
| 86 | return 1 + x; | |
| 87 | } | |
| 88 | ||
| 89 | const xx = x * x; | |
| 90 | const c = x - xx * (P1 + xx * P2); | |
| 91 | const y = 1 + (x * c / (2 - c) - lo + hi); | |
| 92 | ||
| 93 | if (k == 0) { | |
| 94 | return y; | |
| 95 | } else { | |
| 96 | return math.scalbn(y, k); | |
| 97 | } | |
| 98 | } | |
| 99 | ||
| 100 | fn exp64(x_: f64) f64 { | |
| 101 | const half = [_]f64{ 0.5, -0.5 }; | |
| 102 | const ln2hi: f64 = 6.93147180369123816490e-01; | |
| 103 | const ln2lo: f64 = 1.90821492927058770002e-10; | |
| 104 | const invln2: f64 = 1.44269504088896338700e+00; | |
| 105 | const P1: f64 = 1.66666666666666019037e-01; | |
| 106 | const P2: f64 = -2.77777777770155933842e-03; | |
| 107 | const P3: f64 = 6.61375632143793436117e-05; | |
| 108 | const P4: f64 = -1.65339022054652515390e-06; | |
| 109 | const P5: f64 = 4.13813679705723846039e-08; | |
| 110 | ||
| 111 | var x = x_; | |
| 112 | var ux = @bitCast(u64, x); | |
| 113 | var hx = ux >> 32; | |
| 114 | const sign = @intCast(i32, hx >> 31); | |
| 115 | hx &= 0x7FFFFFFF; | |
| 116 | ||
| 117 | if (math.isNan(x)) { | |
| 118 | return x; | |
| 119 | } | |
| 120 | ||
| 121 | // |x| >= 708.39 or nan | |
| 122 | if (hx >= 0x4086232B) { | |
| 123 | // nan | |
| 124 | if (hx > 0x7FF00000) { | |
| 125 | return x; | |
| 126 | } | |
| 127 | if (x > 709.782712893383973096) { | |
| 128 | // overflow if x != inf | |
| 129 | if (!math.isInf(x)) { | |
| 130 | math.raiseOverflow(); | |
| 131 | } | |
| 132 | return math.inf(f64); | |
| 133 | } | |
| 134 | if (x < -708.39641853226410622) { | |
| 135 | // underflow if x != -inf | |
| 136 | // math.doNotOptimizeAway(@as(f32, -0x1.0p-149 / x)); | |
| 137 | if (x < -745.13321910194110842) { | |
| 138 | return 0; | |
| 139 | } | |
| 140 | } | |
| 141 | } | |
| 142 | ||
| 143 | // argument reduction | |
| 144 | var k: i32 = undefined; | |
| 145 | var hi: f64 = undefined; | |
| 146 | var lo: f64 = undefined; | |
| 147 | ||
| 148 | // |x| > 0.5 * ln2 | |
| 149 | if (hx > 0x3FD62E42) { | |
| 150 | // |x| >= 1.5 * ln2 | |
| 151 | if (hx > 0x3FF0A2B2) { | |
| 152 | k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]); | |
| 153 | } else { | |
| 154 | k = 1 - sign - sign; | |
| 155 | } | |
| 156 | ||
| 157 | const dk = @intToFloat(f64, k); | |
| 158 | hi = x - dk * ln2hi; | |
| 159 | lo = dk * ln2lo; | |
| 160 | x = hi - lo; | |
| 161 | } | |
| 162 | // |x| > 2^(-28) | |
| 163 | else if (hx > 0x3E300000) { | |
| 164 | k = 0; | |
| 165 | hi = x; | |
| 166 | lo = 0; | |
| 167 | } else { | |
| 168 | // inexact if x != 0 | |
| 169 | // math.doNotOptimizeAway(0x1.0p1023 + x); | |
| 170 | return 1 + x; | |
| 171 | } | |
| 172 | ||
| 173 | const xx = x * x; | |
| 174 | const c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); | |
| 175 | const y = 1 + (x * c / (2 - c) - lo + hi); | |
| 176 | ||
| 177 | if (k == 0) { | |
| 178 | return y; | |
| 179 | } else { | |
| 180 | return math.scalbn(y, k); | |
| 181 | } | |
| 182 | } | |
| 183 | ||
| 184 | test "math.exp" { | |
| 185 | try expect(exp(@as(f32, 0.0)) == exp32(0.0)); | |
| 186 | try expect(exp(@as(f64, 0.0)) == exp64(0.0)); | |
| 187 | } | |
| 188 | ||
| 189 | test "math.exp32" { | |
| 190 | const epsilon = 0.000001; | |
| 191 | ||
| 192 | try expect(exp32(0.0) == 1.0); | |
| 193 | try expect(math.approxEqAbs(f32, exp32(0.0), 1.0, epsilon)); | |
| 194 | try expect(math.approxEqAbs(f32, exp32(0.2), 1.221403, epsilon)); | |
| 195 | try expect(math.approxEqAbs(f32, exp32(0.8923), 2.440737, epsilon)); | |
| 196 | try expect(math.approxEqAbs(f32, exp32(1.5), 4.481689, epsilon)); | |
| 197 | } | |
| 198 | ||
| 199 | test "math.exp64" { | |
| 200 | const epsilon = 0.000001; | |
| 201 | ||
| 202 | try expect(exp64(0.0) == 1.0); | |
| 203 | try expect(math.approxEqAbs(f64, exp64(0.0), 1.0, epsilon)); | |
| 204 | try expect(math.approxEqAbs(f64, exp64(0.2), 1.221403, epsilon)); | |
| 205 | try expect(math.approxEqAbs(f64, exp64(0.8923), 2.440737, epsilon)); | |
| 206 | try expect(math.approxEqAbs(f64, exp64(1.5), 4.481689, epsilon)); | |
| 207 | } | |
| 208 | ||
| 209 | test "math.exp32.special" { | |
| 210 | try expect(math.isPositiveInf(exp32(math.inf(f32)))); | |
| 211 | try expect(math.isNan(exp32(math.nan(f32)))); | |
| 212 | } | |
| 213 | ||
| 214 | test "math.exp64.special" { | |
| 215 | try expect(math.isPositiveInf(exp64(math.inf(f64)))); | |
| 216 | try expect(math.isNan(exp64(math.nan(f64)))); | |
| 217 | } |
lib/std/math/exp2.zig deleted-465| ... | ... | @@ -1,465 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/exp2f.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/exp2.c | |
| 6 | ||
| 7 | const std = @import("../std.zig"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | /// Returns 2 raised to the power of x (2^x). | |
| 12 | /// | |
| 13 | /// Special Cases: | |
| 14 | /// - exp2(+inf) = +inf | |
| 15 | /// - exp2(nan) = nan | |
| 16 | pub fn exp2(x: anytype) @TypeOf(x) { | |
| 17 | const T = @TypeOf(x); | |
| 18 | return switch (T) { | |
| 19 | f32 => exp2_32(x), | |
| 20 | f64 => exp2_64(x), | |
| 21 | else => @compileError("exp2 not implemented for " ++ @typeName(T)), | |
| 22 | }; | |
| 23 | } | |
| 24 | ||
| 25 | const exp2ft = [_]f64{ | |
| 26 | 0x1.6a09e667f3bcdp-1, | |
| 27 | 0x1.7a11473eb0187p-1, | |
| 28 | 0x1.8ace5422aa0dbp-1, | |
| 29 | 0x1.9c49182a3f090p-1, | |
| 30 | 0x1.ae89f995ad3adp-1, | |
| 31 | 0x1.c199bdd85529cp-1, | |
| 32 | 0x1.d5818dcfba487p-1, | |
| 33 | 0x1.ea4afa2a490dap-1, | |
| 34 | 0x1.0000000000000p+0, | |
| 35 | 0x1.0b5586cf9890fp+0, | |
| 36 | 0x1.172b83c7d517bp+0, | |
| 37 | 0x1.2387a6e756238p+0, | |
| 38 | 0x1.306fe0a31b715p+0, | |
| 39 | 0x1.3dea64c123422p+0, | |
| 40 | 0x1.4bfdad5362a27p+0, | |
| 41 | 0x1.5ab07dd485429p+0, | |
| 42 | }; | |
| 43 | ||
| 44 | fn exp2_32(x: f32) f32 { | |
| 45 | const tblsiz = @intCast(u32, exp2ft.len); | |
| 46 | const redux: f32 = 0x1.8p23 / @intToFloat(f32, tblsiz); | |
| 47 | const P1: f32 = 0x1.62e430p-1; | |
| 48 | const P2: f32 = 0x1.ebfbe0p-3; | |
| 49 | const P3: f32 = 0x1.c6b348p-5; | |
| 50 | const P4: f32 = 0x1.3b2c9cp-7; | |
| 51 | ||
| 52 | var u = @bitCast(u32, x); | |
| 53 | const ix = u & 0x7FFFFFFF; | |
| 54 | ||
| 55 | // |x| > 126 | |
| 56 | if (ix > 0x42FC0000) { | |
| 57 | // nan | |
| 58 | if (ix > 0x7F800000) { | |
| 59 | return x; | |
| 60 | } | |
| 61 | // x >= 128 | |
| 62 | if (u >= 0x43000000 and u < 0x80000000) { | |
| 63 | return x * 0x1.0p127; | |
| 64 | } | |
| 65 | // x < -126 | |
| 66 | if (u >= 0x80000000) { | |
| 67 | if (u >= 0xC3160000 or u & 0x000FFFF != 0) { | |
| 68 | math.doNotOptimizeAway(-0x1.0p-149 / x); | |
| 69 | } | |
| 70 | // x <= -150 | |
| 71 | if (u >= 0x3160000) { | |
| 72 | return 0; | |
| 73 | } | |
| 74 | } | |
| 75 | } | |
| 76 | // |x| <= 0x1p-25 | |
| 77 | else if (ix <= 0x33000000) { | |
| 78 | return 1.0 + x; | |
| 79 | } | |
| 80 | ||
| 81 | // NOTE: musl relies on unsafe behaviours which are replicated below | |
| 82 | // (addition/bit-shift overflow). Appears that this produces the | |
| 83 | // intended result but should confirm how GCC/Clang handle this to ensure. | |
| 84 | ||
| 85 | var uf = x + redux; | |
| 86 | var i_0 = @bitCast(u32, uf); | |
| 87 | i_0 +%= tblsiz / 2; | |
| 88 | ||
| 89 | const k = i_0 / tblsiz; | |
| 90 | const uk = @bitCast(f64, @as(u64, 0x3FF + k) << 52); | |
| 91 | i_0 &= tblsiz - 1; | |
| 92 | uf -= redux; | |
| 93 | ||
| 94 | const z: f64 = x - uf; | |
| 95 | var r: f64 = exp2ft[@intCast(usize, i_0)]; | |
| 96 | const t: f64 = r * z; | |
| 97 | r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); | |
| 98 | return @floatCast(f32, r * uk); | |
| 99 | } | |
| 100 | ||
| 101 | const exp2dt = [_]f64{ | |
| 102 | // exp2(z + eps) eps | |
| 103 | 0x1.6a09e667f3d5dp-1, 0x1.9880p-44, | |
| 104 | 0x1.6b052fa751744p-1, 0x1.8000p-50, | |
| 105 | 0x1.6c012750bd9fep-1, -0x1.8780p-45, | |
| 106 | 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46, | |
| 107 | 0x1.6dfb23c651a29p-1, -0x1.8000p-50, | |
| 108 | 0x1.6ef9298593ae3p-1, -0x1.c000p-52, | |
| 109 | 0x1.6ff7df9519386p-1, -0x1.fd80p-45, | |
| 110 | 0x1.70f7466f42da3p-1, -0x1.c880p-45, | |
| 111 | 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46, | |
| 112 | 0x1.72f8286eacf05p-1, -0x1.8300p-44, | |
| 113 | 0x1.73f9a48a58152p-1, -0x1.0c00p-47, | |
| 114 | 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45, | |
| 115 | 0x1.75feb564267f1p-1, 0x1.3e00p-47, | |
| 116 | 0x1.77024b1ab6d48p-1, -0x1.7d00p-45, | |
| 117 | 0x1.780694fde5d38p-1, -0x1.d000p-50, | |
| 118 | 0x1.790b938ac1d00p-1, 0x1.3000p-49, | |
| 119 | 0x1.7a11473eb0178p-1, -0x1.d000p-49, | |
| 120 | 0x1.7b17b0976d060p-1, 0x1.0400p-45, | |
| 121 | 0x1.7c1ed0130c133p-1, 0x1.0000p-53, | |
| 122 | 0x1.7d26a62ff8636p-1, -0x1.6900p-45, | |
| 123 | 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47, | |
| 124 | 0x1.7f3878491c3e8p-1, -0x1.4580p-45, | |
| 125 | 0x1.80427543e1b4ep-1, 0x1.3000p-44, | |
| 126 | 0x1.814d2add1071ap-1, 0x1.f000p-47, | |
| 127 | 0x1.82589994ccd7ep-1, -0x1.1c00p-45, | |
| 128 | 0x1.8364c1eb942d0p-1, 0x1.9d00p-45, | |
| 129 | 0x1.8471a4623cab5p-1, 0x1.7100p-43, | |
| 130 | 0x1.857f4179f5bbcp-1, 0x1.2600p-45, | |
| 131 | 0x1.868d99b4491afp-1, -0x1.2c40p-44, | |
| 132 | 0x1.879cad931a395p-1, -0x1.3000p-45, | |
| 133 | 0x1.88ac7d98a65b8p-1, -0x1.a800p-45, | |
| 134 | 0x1.89bd0a4785800p-1, -0x1.d000p-49, | |
| 135 | 0x1.8ace5422aa223p-1, 0x1.3280p-44, | |
| 136 | 0x1.8be05bad619fap-1, 0x1.2b40p-43, | |
| 137 | 0x1.8cf3216b54383p-1, -0x1.ed00p-45, | |
| 138 | 0x1.8e06a5e08664cp-1, -0x1.0500p-45, | |
| 139 | 0x1.8f1ae99157807p-1, 0x1.8280p-45, | |
| 140 | 0x1.902fed0282c0ep-1, -0x1.cb00p-46, | |
| 141 | 0x1.9145b0b91ff96p-1, -0x1.5e00p-47, | |
| 142 | 0x1.925c353aa2ff9p-1, 0x1.5400p-48, | |
| 143 | 0x1.93737b0cdc64ap-1, 0x1.7200p-46, | |
| 144 | 0x1.948b82b5f98aep-1, -0x1.9000p-47, | |
| 145 | 0x1.95a44cbc852cbp-1, 0x1.5680p-45, | |
| 146 | 0x1.96bdd9a766f21p-1, -0x1.6d00p-44, | |
| 147 | 0x1.97d829fde4e2ap-1, -0x1.1000p-47, | |
| 148 | 0x1.98f33e47a23a3p-1, 0x1.d000p-45, | |
| 149 | 0x1.9a0f170ca0604p-1, -0x1.8a40p-44, | |
| 150 | 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44, | |
| 151 | 0x1.9c49182a3f15bp-1, 0x1.6b80p-45, | |
| 152 | 0x1.9d674194bb8c5p-1, -0x1.c000p-49, | |
| 153 | 0x1.9e86319e3238ep-1, 0x1.7d00p-46, | |
| 154 | 0x1.9fa5e8d07f302p-1, 0x1.6400p-46, | |
| 155 | 0x1.a0c667b5de54dp-1, -0x1.5000p-48, | |
| 156 | 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47, | |
| 157 | 0x1.a309bec4a2e27p-1, 0x1.ad80p-45, | |
| 158 | 0x1.a42c980460a5dp-1, -0x1.af00p-46, | |
| 159 | 0x1.a5503b23e259bp-1, 0x1.b600p-47, | |
| 160 | 0x1.a674a8af46213p-1, 0x1.8880p-44, | |
| 161 | 0x1.a799e1330b3a7p-1, 0x1.1200p-46, | |
| 162 | 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47, | |
| 163 | 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45, | |
| 164 | 0x1.ab0e521356fb8p-1, 0x1.b700p-45, | |
| 165 | 0x1.ac36bbfd3f381p-1, 0x1.9000p-50, | |
| 166 | 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49, | |
| 167 | 0x1.ae89f995ad2a3p-1, -0x1.c900p-45, | |
| 168 | 0x1.afb4ce622f367p-1, 0x1.6500p-46, | |
| 169 | 0x1.b0e07298db790p-1, 0x1.fd40p-45, | |
| 170 | 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46, | |
| 171 | 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43, | |
| 172 | 0x1.b468415b747e7p-1, -0x1.8380p-44, | |
| 173 | 0x1.b59728de5593ap-1, 0x1.8000p-54, | |
| 174 | 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47, | |
| 175 | 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50, | |
| 176 | 0x1.b928cf22749b2p-1, -0x1.4c00p-47, | |
| 177 | 0x1.ba5b030a10603p-1, -0x1.d700p-47, | |
| 178 | 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47, | |
| 179 | 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47, | |
| 180 | 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46, | |
| 181 | 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46, | |
| 182 | 0x1.c06286141b2e9p-1, -0x1.1400p-46, | |
| 183 | 0x1.c199bdd8552e0p-1, 0x1.be00p-47, | |
| 184 | 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47, | |
| 185 | 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47, | |
| 186 | 0x1.c544778fafd15p-1, 0x1.9660p-44, | |
| 187 | 0x1.c67f12e57d0cbp-1, -0x1.a100p-46, | |
| 188 | 0x1.c7ba88988c1b6p-1, -0x1.8458p-42, | |
| 189 | 0x1.c8f6d9406e733p-1, -0x1.a480p-46, | |
| 190 | 0x1.ca3405751c4dfp-1, 0x1.b000p-51, | |
| 191 | 0x1.cb720dcef9094p-1, 0x1.1400p-47, | |
| 192 | 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48, | |
| 193 | 0x1.cdf0b555dc412p-1, 0x1.3600p-48, | |
| 194 | 0x1.cf3155b5bab3bp-1, -0x1.6900p-47, | |
| 195 | 0x1.d072d4a0789bcp-1, 0x1.9a00p-47, | |
| 196 | 0x1.d1b532b08c8fap-1, -0x1.5e00p-46, | |
| 197 | 0x1.d2f87080d8a85p-1, 0x1.d280p-46, | |
| 198 | 0x1.d43c8eacaa203p-1, 0x1.1a00p-47, | |
| 199 | 0x1.d5818dcfba491p-1, 0x1.f000p-50, | |
| 200 | 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47, | |
| 201 | 0x1.d80e316c9834ep-1, -0x1.cd80p-47, | |
| 202 | 0x1.d955d71ff6090p-1, 0x1.4c00p-48, | |
| 203 | 0x1.da9e603db32aep-1, 0x1.f900p-48, | |
| 204 | 0x1.dbe7cd63a8325p-1, 0x1.9800p-49, | |
| 205 | 0x1.dd321f301b445p-1, -0x1.5200p-48, | |
| 206 | 0x1.de7d5641c05bfp-1, -0x1.d700p-46, | |
| 207 | 0x1.dfc97337b9aecp-1, -0x1.6140p-46, | |
| 208 | 0x1.e11676b197d5ep-1, 0x1.b480p-47, | |
| 209 | 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43, | |
| 210 | 0x1.e3b333b16ee5cp-1, 0x1.c680p-47, | |
| 211 | 0x1.e502ee78b3fb4p-1, -0x1.9300p-47, | |
| 212 | 0x1.e653924676d68p-1, -0x1.5000p-49, | |
| 213 | 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47, | |
| 214 | 0x1.e8f7977cdb726p-1, -0x1.3700p-48, | |
| 215 | 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49, | |
| 216 | 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46, | |
| 217 | 0x1.ecf482d8e680dp-1, 0x1.5500p-48, | |
| 218 | 0x1.ee4aaa2188514p-1, 0x1.6400p-51, | |
| 219 | 0x1.efa1bee615a13p-1, -0x1.e800p-49, | |
| 220 | 0x1.f0f9c1cb64106p-1, -0x1.a880p-48, | |
| 221 | 0x1.f252b376bb963p-1, -0x1.c900p-45, | |
| 222 | 0x1.f3ac948dd7275p-1, 0x1.a000p-53, | |
| 223 | 0x1.f50765b6e4524p-1, -0x1.4f00p-48, | |
| 224 | 0x1.f6632798844fdp-1, 0x1.a800p-51, | |
| 225 | 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48, | |
| 226 | 0x1.f91d802243c82p-1, -0x1.4600p-50, | |
| 227 | 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47, | |
| 228 | 0x1.fbdba3692d511p-1, -0x1.0e00p-51, | |
| 229 | 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46, | |
| 230 | 0x1.fe9d96b2a23eep-1, 0x1.e430p-49, | |
| 231 | 0x1.0000000000000p+0, 0x0.0000p+0, | |
| 232 | 0x1.00b1afa5abcbep+0, -0x1.3400p-52, | |
| 233 | 0x1.0163da9fb3303p+0, -0x1.2170p-46, | |
| 234 | 0x1.02168143b0282p+0, 0x1.a400p-52, | |
| 235 | 0x1.02c9a3e77806cp+0, 0x1.f980p-49, | |
| 236 | 0x1.037d42e11bbcap+0, -0x1.7400p-51, | |
| 237 | 0x1.04315e86e7f89p+0, 0x1.8300p-50, | |
| 238 | 0x1.04e5f72f65467p+0, -0x1.a3f0p-46, | |
| 239 | 0x1.059b0d315855ap+0, -0x1.2840p-47, | |
| 240 | 0x1.0650a0e3c1f95p+0, 0x1.1600p-48, | |
| 241 | 0x1.0706b29ddf71ap+0, 0x1.5240p-46, | |
| 242 | 0x1.07bd42b72a82dp+0, -0x1.9a00p-49, | |
| 243 | 0x1.0874518759bd0p+0, 0x1.6400p-49, | |
| 244 | 0x1.092bdf66607c8p+0, -0x1.0780p-47, | |
| 245 | 0x1.09e3ecac6f383p+0, -0x1.8000p-54, | |
| 246 | 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48, | |
| 247 | 0x1.0b5586cf988fcp+0, -0x1.ac80p-48, | |
| 248 | 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50, | |
| 249 | 0x1.0cc922b724816p+0, 0x1.5200p-47, | |
| 250 | 0x1.0d83b23395dd8p+0, -0x1.ad00p-48, | |
| 251 | 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46, | |
| 252 | 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47, | |
| 253 | 0x1.0fb66affed2f0p+0, -0x1.d300p-47, | |
| 254 | 0x1.1073028d7234bp+0, 0x1.1500p-48, | |
| 255 | 0x1.11301d0125b5bp+0, 0x1.c000p-49, | |
| 256 | 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46, | |
| 257 | 0x1.12abdc06c31d5p+0, 0x1.8400p-49, | |
| 258 | 0x1.136a814f2047dp+0, -0x1.ed00p-47, | |
| 259 | 0x1.1429aaea92de9p+0, 0x1.8e00p-49, | |
| 260 | 0x1.14e95934f3138p+0, 0x1.b400p-49, | |
| 261 | 0x1.15a98c8a58e71p+0, 0x1.5300p-47, | |
| 262 | 0x1.166a45471c3dfp+0, 0x1.3380p-47, | |
| 263 | 0x1.172b83c7d5211p+0, 0x1.8d40p-45, | |
| 264 | 0x1.17ed48695bb9fp+0, -0x1.5d00p-47, | |
| 265 | 0x1.18af9388c8d93p+0, -0x1.c880p-46, | |
| 266 | 0x1.1972658375d66p+0, 0x1.1f00p-46, | |
| 267 | 0x1.1a35beb6fcba7p+0, 0x1.0480p-46, | |
| 268 | 0x1.1af99f81387e3p+0, -0x1.7390p-43, | |
| 269 | 0x1.1bbe084045d54p+0, 0x1.4e40p-45, | |
| 270 | 0x1.1c82f95281c43p+0, -0x1.a200p-47, | |
| 271 | 0x1.1d4873168b9b2p+0, 0x1.3800p-49, | |
| 272 | 0x1.1e0e75eb44031p+0, 0x1.ac00p-49, | |
| 273 | 0x1.1ed5022fcd938p+0, 0x1.1900p-47, | |
| 274 | 0x1.1f9c18438cdf7p+0, -0x1.b780p-46, | |
| 275 | 0x1.2063b88628d8fp+0, 0x1.d940p-45, | |
| 276 | 0x1.212be3578a81ep+0, 0x1.8000p-50, | |
| 277 | 0x1.21f49917ddd41p+0, 0x1.b340p-45, | |
| 278 | 0x1.22bdda2791323p+0, 0x1.9f80p-46, | |
| 279 | 0x1.2387a6e7561e7p+0, -0x1.9c80p-46, | |
| 280 | 0x1.2451ffb821427p+0, 0x1.2300p-47, | |
| 281 | 0x1.251ce4fb2a602p+0, -0x1.3480p-46, | |
| 282 | 0x1.25e85711eceb0p+0, 0x1.2700p-46, | |
| 283 | 0x1.26b4565e27d16p+0, 0x1.1d00p-46, | |
| 284 | 0x1.2780e341de00fp+0, 0x1.1ee0p-44, | |
| 285 | 0x1.284dfe1f5633ep+0, -0x1.4c00p-46, | |
| 286 | 0x1.291ba7591bb30p+0, -0x1.3d80p-46, | |
| 287 | 0x1.29e9df51fdf09p+0, 0x1.8b00p-47, | |
| 288 | 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45, | |
| 289 | 0x1.2b87fd0dada3ap+0, 0x1.a340p-45, | |
| 290 | 0x1.2c57e39771af9p+0, -0x1.0800p-46, | |
| 291 | 0x1.2d285a6e402d9p+0, -0x1.ed00p-47, | |
| 292 | 0x1.2df961f641579p+0, -0x1.4200p-48, | |
| 293 | 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45, | |
| 294 | 0x1.2f9d24abd8822p+0, -0x1.6300p-46, | |
| 295 | 0x1.306fe0a31b625p+0, -0x1.2360p-44, | |
| 296 | 0x1.31432edeea50bp+0, -0x1.0df8p-40, | |
| 297 | 0x1.32170fc4cd7b8p+0, -0x1.2480p-45, | |
| 298 | 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45, | |
| 299 | 0x1.33c08b2641766p+0, 0x1.ed00p-46, | |
| 300 | 0x1.3496266e3fa27p+0, -0x1.c000p-50, | |
| 301 | 0x1.356c55f929f0fp+0, -0x1.0d80p-44, | |
| 302 | 0x1.36431a2de88b9p+0, 0x1.2c80p-45, | |
| 303 | 0x1.371a7373aaa39p+0, 0x1.0600p-45, | |
| 304 | 0x1.37f26231e74fep+0, -0x1.6600p-46, | |
| 305 | 0x1.38cae6d05d838p+0, -0x1.ae00p-47, | |
| 306 | 0x1.39a401b713ec3p+0, -0x1.4720p-43, | |
| 307 | 0x1.3a7db34e5a020p+0, 0x1.8200p-47, | |
| 308 | 0x1.3b57fbfec6e95p+0, 0x1.e800p-44, | |
| 309 | 0x1.3c32dc313a8f2p+0, 0x1.f800p-49, | |
| 310 | 0x1.3d0e544ede122p+0, -0x1.7a00p-46, | |
| 311 | 0x1.3dea64c1234bbp+0, 0x1.6300p-45, | |
| 312 | 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43, | |
| 313 | 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44, | |
| 314 | 0x1.40822c367a0bbp+0, 0x1.5b80p-45, | |
| 315 | 0x1.4160a21f72e95p+0, 0x1.ec00p-46, | |
| 316 | 0x1.423fb27094646p+0, -0x1.3600p-46, | |
| 317 | 0x1.431f5d950a920p+0, 0x1.3980p-45, | |
| 318 | 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48, | |
| 319 | 0x1.44e0860618919p+0, -0x1.6c00p-48, | |
| 320 | 0x1.45c2042a7d201p+0, -0x1.bc00p-47, | |
| 321 | 0x1.46a41ed1d0016p+0, -0x1.2800p-46, | |
| 322 | 0x1.4786d668b3326p+0, 0x1.0e00p-44, | |
| 323 | 0x1.486a2b5c13c00p+0, -0x1.d400p-45, | |
| 324 | 0x1.494e1e192af04p+0, 0x1.c200p-47, | |
| 325 | 0x1.4a32af0d7d372p+0, -0x1.e500p-46, | |
| 326 | 0x1.4b17dea6db801p+0, 0x1.7800p-47, | |
| 327 | 0x1.4bfdad53629e1p+0, -0x1.3800p-46, | |
| 328 | 0x1.4ce41b817c132p+0, 0x1.0800p-47, | |
| 329 | 0x1.4dcb299fddddbp+0, 0x1.c700p-45, | |
| 330 | 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46, | |
| 331 | 0x1.4f9b2769d2d02p+0, 0x1.9200p-46, | |
| 332 | 0x1.508417f4531c1p+0, -0x1.8c00p-47, | |
| 333 | 0x1.516daa2cf662ap+0, -0x1.a000p-48, | |
| 334 | 0x1.5257de83f51eap+0, 0x1.a080p-43, | |
| 335 | 0x1.5342b569d4edap+0, -0x1.6d80p-45, | |
| 336 | 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44, | |
| 337 | 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43, | |
| 338 | 0x1.56070dde9116bp+0, 0x1.4b00p-45, | |
| 339 | 0x1.56f4736b529dep+0, 0x1.15a0p-43, | |
| 340 | 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45, | |
| 341 | 0x1.58d12d497c76fp+0, -0x1.3080p-45, | |
| 342 | 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43, | |
| 343 | 0x1.5ab07dd485427p+0, -0x1.4000p-51, | |
| 344 | 0x1.5ba11fba87af4p+0, 0x1.0080p-44, | |
| 345 | 0x1.5c9268a59460bp+0, -0x1.6c80p-45, | |
| 346 | 0x1.5d84590998e3fp+0, 0x1.69a0p-43, | |
| 347 | 0x1.5e76f15ad20e1p+0, -0x1.b400p-46, | |
| 348 | 0x1.5f6a320dcebcap+0, 0x1.7700p-46, | |
| 349 | 0x1.605e1b976dcb8p+0, 0x1.6f80p-45, | |
| 350 | 0x1.6152ae6cdf715p+0, 0x1.1000p-47, | |
| 351 | 0x1.6247eb03a5531p+0, -0x1.5d00p-46, | |
| 352 | 0x1.633dd1d1929b5p+0, -0x1.2d00p-46, | |
| 353 | 0x1.6434634ccc313p+0, -0x1.a800p-49, | |
| 354 | 0x1.652b9febc8efap+0, -0x1.8600p-45, | |
| 355 | 0x1.6623882553397p+0, 0x1.1fe0p-40, | |
| 356 | 0x1.671c1c708328ep+0, -0x1.7200p-44, | |
| 357 | 0x1.68155d44ca97ep+0, 0x1.6800p-49, | |
| 358 | 0x1.690f4b19e9471p+0, -0x1.9780p-45, | |
| 359 | }; | |
| 360 | ||
| 361 | fn exp2_64(x: f64) f64 { | |
| 362 | const tblsiz: u32 = @intCast(u32, exp2dt.len / 2); | |
| 363 | const redux: f64 = 0x1.8p52 / @intToFloat(f64, tblsiz); | |
| 364 | const P1: f64 = 0x1.62e42fefa39efp-1; | |
| 365 | const P2: f64 = 0x1.ebfbdff82c575p-3; | |
| 366 | const P3: f64 = 0x1.c6b08d704a0a6p-5; | |
| 367 | const P4: f64 = 0x1.3b2ab88f70400p-7; | |
| 368 | const P5: f64 = 0x1.5d88003875c74p-10; | |
| 369 | ||
| 370 | const ux = @bitCast(u64, x); | |
| 371 | const ix = @intCast(u32, ux >> 32) & 0x7FFFFFFF; | |
| 372 | ||
| 373 | // TODO: This should be handled beneath. | |
| 374 | if (math.isNan(x)) { | |
| 375 | return math.nan(f64); | |
| 376 | } | |
| 377 | ||
| 378 | // |x| >= 1022 or nan | |
| 379 | if (ix >= 0x408FF000) { | |
| 380 | // x >= 1024 or nan | |
| 381 | if (ix >= 0x40900000 and ux >> 63 == 0) { | |
| 382 | math.raiseOverflow(); | |
| 383 | return math.inf(f64); | |
| 384 | } | |
| 385 | // -inf or -nan | |
| 386 | if (ix >= 0x7FF00000) { | |
| 387 | return -1 / x; | |
| 388 | } | |
| 389 | // x <= -1022 | |
| 390 | if (ux >> 63 != 0) { | |
| 391 | // underflow | |
| 392 | if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) { | |
| 393 | math.doNotOptimizeAway(@floatCast(f32, -0x1.0p-149 / x)); | |
| 394 | } | |
| 395 | if (x <= -1075) { | |
| 396 | return 0; | |
| 397 | } | |
| 398 | } | |
| 399 | } | |
| 400 | // |x| < 0x1p-54 | |
| 401 | else if (ix < 0x3C900000) { | |
| 402 | return 1.0 + x; | |
| 403 | } | |
| 404 | ||
| 405 | // NOTE: musl relies on unsafe behaviours which are replicated below | |
| 406 | // (addition overflow, division truncation, casting). Appears that this | |
| 407 | // produces the intended result but should confirm how GCC/Clang handle this | |
| 408 | // to ensure. | |
| 409 | ||
| 410 | // reduce x | |
| 411 | var uf: f64 = x + redux; | |
| 412 | // NOTE: musl performs an implicit 64-bit to 32-bit u32 truncation here | |
| 413 | var i_0: u32 = @truncate(u32, @bitCast(u64, uf)); | |
| 414 | i_0 +%= tblsiz / 2; | |
| 415 | ||
| 416 | const k: u32 = i_0 / tblsiz * tblsiz; | |
| 417 | const ik: i32 = @divTrunc(@bitCast(i32, k), tblsiz); | |
| 418 | i_0 %= tblsiz; | |
| 419 | uf -= redux; | |
| 420 | ||
| 421 | // r = exp2(y) = exp2t[i_0] * p(z - eps[i]) | |
| 422 | var z: f64 = x - uf; | |
| 423 | const t: f64 = exp2dt[@intCast(usize, 2 * i_0)]; | |
| 424 | z -= exp2dt[@intCast(usize, 2 * i_0 + 1)]; | |
| 425 | const r: f64 = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); | |
| 426 | ||
| 427 | return math.scalbn(r, ik); | |
| 428 | } | |
| 429 | ||
| 430 | test "math.exp2" { | |
| 431 | try expect(exp2(@as(f32, 0.8923)) == exp2_32(0.8923)); | |
| 432 | try expect(exp2(@as(f64, 0.8923)) == exp2_64(0.8923)); | |
| 433 | } | |
| 434 | ||
| 435 | test "math.exp2_32" { | |
| 436 | const epsilon = 0.000001; | |
| 437 | ||
| 438 | try expect(exp2_32(0.0) == 1.0); | |
| 439 | try expect(math.approxEqAbs(f32, exp2_32(0.2), 1.148698, epsilon)); | |
| 440 | try expect(math.approxEqAbs(f32, exp2_32(0.8923), 1.856133, epsilon)); | |
| 441 | try expect(math.approxEqAbs(f32, exp2_32(1.5), 2.828427, epsilon)); | |
| 442 | try expect(math.approxEqAbs(f32, exp2_32(37.45), 187747237888, epsilon)); | |
| 443 | try expect(math.approxEqAbs(f32, exp2_32(-1), 0.5, epsilon)); | |
| 444 | } | |
| 445 | ||
| 446 | test "math.exp2_64" { | |
| 447 | const epsilon = 0.000001; | |
| 448 | ||
| 449 | try expect(exp2_64(0.0) == 1.0); | |
| 450 | try expect(math.approxEqAbs(f64, exp2_64(0.2), 1.148698, epsilon)); | |
| 451 | try expect(math.approxEqAbs(f64, exp2_64(0.8923), 1.856133, epsilon)); | |
| 452 | try expect(math.approxEqAbs(f64, exp2_64(1.5), 2.828427, epsilon)); | |
| 453 | try expect(math.approxEqAbs(f64, exp2_64(-1), 0.5, epsilon)); | |
| 454 | try expect(math.approxEqAbs(f64, exp2_64(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1, epsilon)); | |
| 455 | } | |
| 456 | ||
| 457 | test "math.exp2_32.special" { | |
| 458 | try expect(math.isPositiveInf(exp2_32(math.inf(f32)))); | |
| 459 | try expect(math.isNan(exp2_32(math.nan(f32)))); | |
| 460 | } | |
| 461 | ||
| 462 | test "math.exp2_64.special" { | |
| 463 | try expect(math.isPositiveInf(exp2_64(math.inf(f64)))); | |
| 464 | try expect(math.isNan(exp2_64(math.nan(f64)))); | |
| 465 | } |
lib/std/math/expo2.zig+2-2| ... | ... | @@ -22,7 +22,7 @@ fn expo2f(x: f32) f32 { |
| 22 | 22 | |
| 23 | 23 | const u = (0x7F + k / 2) << 23; |
| 24 | 24 | const scale = @bitCast(f32, u); |
| 25 | return math.exp(x - kln2) * scale * scale; | |
| 25 | return @exp(x - kln2) * scale * scale; | |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | fn expo2d(x: f64) f64 { |
| ... | ... | @@ -31,5 +31,5 @@ fn expo2d(x: f64) f64 { |
| 31 | 31 | |
| 32 | 32 | const u = (0x3FF + k / 2) << 20; |
| 33 | 33 | const scale = @bitCast(f64, @as(u64, u) << 32); |
| 34 | return math.exp(x - kln2) * scale * scale; | |
| 34 | return @exp(x - kln2) * scale * scale; | |
| 35 | 35 | } |
lib/std/math/fabs.zig deleted-45| ... | ... | @@ -1,45 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const math = std.math; | |
| 3 | const expect = std.testing.expect; | |
| 4 | ||
| 5 | /// Returns the absolute value of x. | |
| 6 | /// | |
| 7 | /// Special Cases: | |
| 8 | /// - fabs(+-inf) = +inf | |
| 9 | /// - fabs(nan) = nan | |
| 10 | pub fn fabs(x: anytype) @TypeOf(x) { | |
| 11 | const T = @TypeOf(x); | |
| 12 | const TBits = std.meta.Int(.unsigned, @bitSizeOf(T)); | |
| 13 | if (@typeInfo(T) != .Float) { | |
| 14 | @compileError("fabs not implemented for " ++ @typeName(T)); | |
| 15 | } | |
| 16 | ||
| 17 | const float_bits = @bitCast(TBits, x); | |
| 18 | const remove_sign = ~@as(TBits, 0) >> 1; | |
| 19 | ||
| 20 | return @bitCast(T, float_bits & remove_sign); | |
| 21 | } | |
| 22 | ||
| 23 | test "math.fabs" { | |
| 24 | // TODO add support for c_longdouble here | |
| 25 | inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| { | |
| 26 | // normals | |
| 27 | try expect(fabs(@as(T, 1.0)) == 1.0); | |
| 28 | try expect(fabs(@as(T, -1.0)) == 1.0); | |
| 29 | try expect(fabs(math.floatMin(T)) == math.floatMin(T)); | |
| 30 | try expect(fabs(-math.floatMin(T)) == math.floatMin(T)); | |
| 31 | try expect(fabs(math.floatMax(T)) == math.floatMax(T)); | |
| 32 | try expect(fabs(-math.floatMax(T)) == math.floatMax(T)); | |
| 33 | ||
| 34 | // subnormals | |
| 35 | try expect(fabs(@as(T, 0.0)) == 0.0); | |
| 36 | try expect(fabs(@as(T, -0.0)) == 0.0); | |
| 37 | try expect(fabs(math.floatTrueMin(T)) == math.floatTrueMin(T)); | |
| 38 | try expect(fabs(-math.floatTrueMin(T)) == math.floatTrueMin(T)); | |
| 39 | ||
| 40 | // non-finite numbers | |
| 41 | try expect(math.isPositiveInf(fabs(math.inf(T)))); | |
| 42 | try expect(math.isPositiveInf(fabs(-math.inf(T)))); | |
| 43 | try expect(math.isNan(fabs(math.nan(T)))); | |
| 44 | } | |
| 45 | } |
lib/std/math/floor.zig deleted-221| ... | ... | @@ -1,221 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c | |
| 6 | ||
| 7 | const expect = std.testing.expect; | |
| 8 | const std = @import("../std.zig"); | |
| 9 | const math = std.math; | |
| 10 | ||
| 11 | /// Returns the greatest integer value less than or equal to x. | |
| 12 | /// | |
| 13 | /// Special Cases: | |
| 14 | /// - floor(+-0) = +-0 | |
| 15 | /// - floor(+-inf) = +-inf | |
| 16 | /// - floor(nan) = nan | |
| 17 | pub fn floor(x: anytype) @TypeOf(x) { | |
| 18 | const T = @TypeOf(x); | |
| 19 | return switch (T) { | |
| 20 | f16 => floor16(x), | |
| 21 | f32 => floor32(x), | |
| 22 | f64 => floor64(x), | |
| 23 | f128 => floor128(x), | |
| 24 | ||
| 25 | // TODO this is not correct for some targets | |
| 26 | c_longdouble => @floatCast(c_longdouble, floor128(x)), | |
| 27 | ||
| 28 | else => @compileError("floor not implemented for " ++ @typeName(T)), | |
| 29 | }; | |
| 30 | } | |
| 31 | ||
| 32 | fn floor16(x: f16) f16 { | |
| 33 | var u = @bitCast(u16, x); | |
| 34 | const e = @intCast(i16, (u >> 10) & 31) - 15; | |
| 35 | var m: u16 = undefined; | |
| 36 | ||
| 37 | // TODO: Shouldn't need this explicit check. | |
| 38 | if (x == 0.0) { | |
| 39 | return x; | |
| 40 | } | |
| 41 | ||
| 42 | if (e >= 10) { | |
| 43 | return x; | |
| 44 | } | |
| 45 | ||
| 46 | if (e >= 0) { | |
| 47 | m = @as(u16, 1023) >> @intCast(u4, e); | |
| 48 | if (u & m == 0) { | |
| 49 | return x; | |
| 50 | } | |
| 51 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 52 | if (u >> 15 != 0) { | |
| 53 | u += m; | |
| 54 | } | |
| 55 | return @bitCast(f16, u & ~m); | |
| 56 | } else { | |
| 57 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 58 | if (u >> 15 == 0) { | |
| 59 | return 0.0; | |
| 60 | } else { | |
| 61 | return -1.0; | |
| 62 | } | |
| 63 | } | |
| 64 | } | |
| 65 | ||
| 66 | fn floor32(x: f32) f32 { | |
| 67 | var u = @bitCast(u32, x); | |
| 68 | const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F; | |
| 69 | var m: u32 = undefined; | |
| 70 | ||
| 71 | // TODO: Shouldn't need this explicit check. | |
| 72 | if (x == 0.0) { | |
| 73 | return x; | |
| 74 | } | |
| 75 | ||
| 76 | if (e >= 23) { | |
| 77 | return x; | |
| 78 | } | |
| 79 | ||
| 80 | if (e >= 0) { | |
| 81 | m = @as(u32, 0x007FFFFF) >> @intCast(u5, e); | |
| 82 | if (u & m == 0) { | |
| 83 | return x; | |
| 84 | } | |
| 85 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 86 | if (u >> 31 != 0) { | |
| 87 | u += m; | |
| 88 | } | |
| 89 | return @bitCast(f32, u & ~m); | |
| 90 | } else { | |
| 91 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 92 | if (u >> 31 == 0) { | |
| 93 | return 0.0; | |
| 94 | } else { | |
| 95 | return -1.0; | |
| 96 | } | |
| 97 | } | |
| 98 | } | |
| 99 | ||
| 100 | fn floor64(x: f64) f64 { | |
| 101 | const f64_toint = 1.0 / math.floatEps(f64); | |
| 102 | ||
| 103 | const u = @bitCast(u64, x); | |
| 104 | const e = (u >> 52) & 0x7FF; | |
| 105 | var y: f64 = undefined; | |
| 106 | ||
| 107 | if (e >= 0x3FF + 52 or x == 0) { | |
| 108 | return x; | |
| 109 | } | |
| 110 | ||
| 111 | if (u >> 63 != 0) { | |
| 112 | y = x - f64_toint + f64_toint - x; | |
| 113 | } else { | |
| 114 | y = x + f64_toint - f64_toint - x; | |
| 115 | } | |
| 116 | ||
| 117 | if (e <= 0x3FF - 1) { | |
| 118 | math.doNotOptimizeAway(y); | |
| 119 | if (u >> 63 != 0) { | |
| 120 | return -1.0; | |
| 121 | } else { | |
| 122 | return 0.0; | |
| 123 | } | |
| 124 | } else if (y > 0) { | |
| 125 | return x + y - 1; | |
| 126 | } else { | |
| 127 | return x + y; | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | fn floor128(x: f128) f128 { | |
| 132 | const f128_toint = 1.0 / math.floatEps(f128); | |
| 133 | ||
| 134 | const u = @bitCast(u128, x); | |
| 135 | const e = (u >> 112) & 0x7FFF; | |
| 136 | var y: f128 = undefined; | |
| 137 | ||
| 138 | if (e >= 0x3FFF + 112 or x == 0) return x; | |
| 139 | ||
| 140 | if (u >> 127 != 0) { | |
| 141 | y = x - f128_toint + f128_toint - x; | |
| 142 | } else { | |
| 143 | y = x + f128_toint - f128_toint - x; | |
| 144 | } | |
| 145 | ||
| 146 | if (e <= 0x3FFF - 1) { | |
| 147 | math.doNotOptimizeAway(y); | |
| 148 | if (u >> 127 != 0) { | |
| 149 | return -1.0; | |
| 150 | } else { | |
| 151 | return 0.0; | |
| 152 | } | |
| 153 | } else if (y > 0) { | |
| 154 | return x + y - 1; | |
| 155 | } else { | |
| 156 | return x + y; | |
| 157 | } | |
| 158 | } | |
| 159 | ||
| 160 | test "math.floor" { | |
| 161 | try expect(floor(@as(f16, 1.3)) == floor16(1.3)); | |
| 162 | try expect(floor(@as(f32, 1.3)) == floor32(1.3)); | |
| 163 | try expect(floor(@as(f64, 1.3)) == floor64(1.3)); | |
| 164 | try expect(floor(@as(f128, 1.3)) == floor128(1.3)); | |
| 165 | } | |
| 166 | ||
| 167 | test "math.floor16" { | |
| 168 | try expect(floor16(1.3) == 1.0); | |
| 169 | try expect(floor16(-1.3) == -2.0); | |
| 170 | try expect(floor16(0.2) == 0.0); | |
| 171 | } | |
| 172 | ||
| 173 | test "math.floor32" { | |
| 174 | try expect(floor32(1.3) == 1.0); | |
| 175 | try expect(floor32(-1.3) == -2.0); | |
| 176 | try expect(floor32(0.2) == 0.0); | |
| 177 | } | |
| 178 | ||
| 179 | test "math.floor64" { | |
| 180 | try expect(floor64(1.3) == 1.0); | |
| 181 | try expect(floor64(-1.3) == -2.0); | |
| 182 | try expect(floor64(0.2) == 0.0); | |
| 183 | } | |
| 184 | ||
| 185 | test "math.floor128" { | |
| 186 | try expect(floor128(1.3) == 1.0); | |
| 187 | try expect(floor128(-1.3) == -2.0); | |
| 188 | try expect(floor128(0.2) == 0.0); | |
| 189 | } | |
| 190 | ||
| 191 | test "math.floor16.special" { | |
| 192 | try expect(floor16(0.0) == 0.0); | |
| 193 | try expect(floor16(-0.0) == -0.0); | |
| 194 | try expect(math.isPositiveInf(floor16(math.inf(f16)))); | |
| 195 | try expect(math.isNegativeInf(floor16(-math.inf(f16)))); | |
| 196 | try expect(math.isNan(floor16(math.nan(f16)))); | |
| 197 | } | |
| 198 | ||
| 199 | test "math.floor32.special" { | |
| 200 | try expect(floor32(0.0) == 0.0); | |
| 201 | try expect(floor32(-0.0) == -0.0); | |
| 202 | try expect(math.isPositiveInf(floor32(math.inf(f32)))); | |
| 203 | try expect(math.isNegativeInf(floor32(-math.inf(f32)))); | |
| 204 | try expect(math.isNan(floor32(math.nan(f32)))); | |
| 205 | } | |
| 206 | ||
| 207 | test "math.floor64.special" { | |
| 208 | try expect(floor64(0.0) == 0.0); | |
| 209 | try expect(floor64(-0.0) == -0.0); | |
| 210 | try expect(math.isPositiveInf(floor64(math.inf(f64)))); | |
| 211 | try expect(math.isNegativeInf(floor64(-math.inf(f64)))); | |
| 212 | try expect(math.isNan(floor64(math.nan(f64)))); | |
| 213 | } | |
| 214 | ||
| 215 | test "math.floor128.special" { | |
| 216 | try expect(floor128(0.0) == 0.0); | |
| 217 | try expect(floor128(-0.0) == -0.0); | |
| 218 | try expect(math.isPositiveInf(floor128(math.inf(f128)))); | |
| 219 | try expect(math.isNegativeInf(floor128(-math.inf(f128)))); | |
| 220 | try expect(math.isNan(floor128(math.nan(f128)))); | |
| 221 | } |
lib/std/math/fma.zig deleted-339| ... | ... | @@ -1,339 +0,0 @@ |
| 1 | // Ported from musl, which is MIT licensed: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/fmal.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/fmaf.c | |
| 6 | // https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c | |
| 7 | ||
| 8 | const std = @import("../std.zig"); | |
| 9 | const math = std.math; | |
| 10 | const expect = std.testing.expect; | |
| 11 | ||
| 12 | /// Returns x * y + z with a single rounding error. | |
| 13 | pub fn fma(comptime T: type, x: T, y: T, z: T) T { | |
| 14 | return switch (T) { | |
| 15 | f32 => fma32(x, y, z), | |
| 16 | f64 => fma64(x, y, z), | |
| 17 | f128 => fma128(x, y, z), | |
| 18 | ||
| 19 | // TODO this is not correct for some targets | |
| 20 | c_longdouble => @floatCast(c_longdouble, fma128(x, y, z)), | |
| 21 | ||
| 22 | f80 => @floatCast(f80, fma128(x, y, z)), | |
| 23 | ||
| 24 | else => @compileError("fma not implemented for " ++ @typeName(T)), | |
| 25 | }; | |
| 26 | } | |
| 27 | ||
| 28 | fn fma32(x: f32, y: f32, z: f32) f32 { | |
| 29 | const xy = @as(f64, x) * y; | |
| 30 | const xy_z = xy + z; | |
| 31 | const u = @bitCast(u64, xy_z); | |
| 32 | const e = (u >> 52) & 0x7FF; | |
| 33 | ||
| 34 | if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or (xy_z - xy == z and xy_z - z == xy)) { | |
| 35 | return @floatCast(f32, xy_z); | |
| 36 | } else { | |
| 37 | // TODO: Handle inexact case with double-rounding | |
| 38 | return @floatCast(f32, xy_z); | |
| 39 | } | |
| 40 | } | |
| 41 | ||
| 42 | // NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately. | |
| 43 | fn fma64(x: f64, y: f64, z: f64) f64 { | |
| 44 | if (!math.isFinite(x) or !math.isFinite(y)) { | |
| 45 | return x * y + z; | |
| 46 | } | |
| 47 | if (!math.isFinite(z)) { | |
| 48 | return z; | |
| 49 | } | |
| 50 | if (x == 0.0 or y == 0.0) { | |
| 51 | return x * y + z; | |
| 52 | } | |
| 53 | if (z == 0.0) { | |
| 54 | return x * y; | |
| 55 | } | |
| 56 | ||
| 57 | const x1 = math.frexp(x); | |
| 58 | var ex = x1.exponent; | |
| 59 | var xs = x1.significand; | |
| 60 | const x2 = math.frexp(y); | |
| 61 | var ey = x2.exponent; | |
| 62 | var ys = x2.significand; | |
| 63 | const x3 = math.frexp(z); | |
| 64 | var ez = x3.exponent; | |
| 65 | var zs = x3.significand; | |
| 66 | ||
| 67 | var spread = ex + ey - ez; | |
| 68 | if (spread <= 53 * 2) { | |
| 69 | zs = math.scalbn(zs, -spread); | |
| 70 | } else { | |
| 71 | zs = math.copysign(f64, math.floatMin(f64), zs); | |
| 72 | } | |
| 73 | ||
| 74 | const xy = dd_mul(xs, ys); | |
| 75 | const r = dd_add(xy.hi, zs); | |
| 76 | spread = ex + ey; | |
| 77 | ||
| 78 | if (r.hi == 0.0) { | |
| 79 | return xy.hi + zs + math.scalbn(xy.lo, spread); | |
| 80 | } | |
| 81 | ||
| 82 | const adj = add_adjusted(r.lo, xy.lo); | |
| 83 | if (spread + math.ilogb(r.hi) > -1023) { | |
| 84 | return math.scalbn(r.hi + adj, spread); | |
| 85 | } else { | |
| 86 | return add_and_denorm(r.hi, adj, spread); | |
| 87 | } | |
| 88 | } | |
| 89 | ||
| 90 | const dd = struct { | |
| 91 | hi: f64, | |
| 92 | lo: f64, | |
| 93 | }; | |
| 94 | ||
| 95 | fn dd_add(a: f64, b: f64) dd { | |
| 96 | var ret: dd = undefined; | |
| 97 | ret.hi = a + b; | |
| 98 | const s = ret.hi - a; | |
| 99 | ret.lo = (a - (ret.hi - s)) + (b - s); | |
| 100 | return ret; | |
| 101 | } | |
| 102 | ||
| 103 | fn dd_mul(a: f64, b: f64) dd { | |
| 104 | var ret: dd = undefined; | |
| 105 | const split: f64 = 0x1.0p27 + 1.0; | |
| 106 | ||
| 107 | var p = a * split; | |
| 108 | var ha = a - p; | |
| 109 | ha += p; | |
| 110 | var la = a - ha; | |
| 111 | ||
| 112 | p = b * split; | |
| 113 | var hb = b - p; | |
| 114 | hb += p; | |
| 115 | var lb = b - hb; | |
| 116 | ||
| 117 | p = ha * hb; | |
| 118 | var q = ha * lb + la * hb; | |
| 119 | ||
| 120 | ret.hi = p + q; | |
| 121 | ret.lo = p - ret.hi + q + la * lb; | |
| 122 | return ret; | |
| 123 | } | |
| 124 | ||
| 125 | fn add_adjusted(a: f64, b: f64) f64 { | |
| 126 | var sum = dd_add(a, b); | |
| 127 | if (sum.lo != 0) { | |
| 128 | var uhii = @bitCast(u64, sum.hi); | |
| 129 | if (uhii & 1 == 0) { | |
| 130 | // hibits += copysign(1.0, sum.hi, sum.lo) | |
| 131 | const uloi = @bitCast(u64, sum.lo); | |
| 132 | uhii += 1 - ((uhii ^ uloi) >> 62); | |
| 133 | sum.hi = @bitCast(f64, uhii); | |
| 134 | } | |
| 135 | } | |
| 136 | return sum.hi; | |
| 137 | } | |
| 138 | ||
| 139 | fn add_and_denorm(a: f64, b: f64, scale: i32) f64 { | |
| 140 | var sum = dd_add(a, b); | |
| 141 | if (sum.lo != 0) { | |
| 142 | var uhii = @bitCast(u64, sum.hi); | |
| 143 | const bits_lost = -@intCast(i32, (uhii >> 52) & 0x7FF) - scale + 1; | |
| 144 | if ((bits_lost != 1) == (uhii & 1 != 0)) { | |
| 145 | const uloi = @bitCast(u64, sum.lo); | |
| 146 | uhii += 1 - (((uhii ^ uloi) >> 62) & 2); | |
| 147 | sum.hi = @bitCast(f64, uhii); | |
| 148 | } | |
| 149 | } | |
| 150 | return math.scalbn(sum.hi, scale); | |
| 151 | } | |
| 152 | ||
| 153 | /// A struct that represents a floating-point number with twice the precision | |
| 154 | /// of f128. We maintain the invariant that "hi" stores the high-order | |
| 155 | /// bits of the result. | |
| 156 | const dd128 = struct { | |
| 157 | hi: f128, | |
| 158 | lo: f128, | |
| 159 | }; | |
| 160 | ||
| 161 | /// Compute a+b exactly, returning the exact result in a struct dd. We assume | |
| 162 | /// that both a and b are finite, but make no assumptions about their relative | |
| 163 | /// magnitudes. | |
| 164 | fn dd_add128(a: f128, b: f128) dd128 { | |
| 165 | var ret: dd128 = undefined; | |
| 166 | ret.hi = a + b; | |
| 167 | const s = ret.hi - a; | |
| 168 | ret.lo = (a - (ret.hi - s)) + (b - s); | |
| 169 | return ret; | |
| 170 | } | |
| 171 | ||
| 172 | /// Compute a+b, with a small tweak: The least significant bit of the | |
| 173 | /// result is adjusted into a sticky bit summarizing all the bits that | |
| 174 | /// were lost to rounding. This adjustment negates the effects of double | |
| 175 | /// rounding when the result is added to another number with a higher | |
| 176 | /// exponent. For an explanation of round and sticky bits, see any reference | |
| 177 | /// on FPU design, e.g., | |
| 178 | /// | |
| 179 | /// J. Coonen. An Implementation Guide to a Proposed Standard for | |
| 180 | /// Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. | |
| 181 | fn add_adjusted128(a: f128, b: f128) f128 { | |
| 182 | var sum = dd_add128(a, b); | |
| 183 | if (sum.lo != 0) { | |
| 184 | var uhii = @bitCast(u128, sum.hi); | |
| 185 | if (uhii & 1 == 0) { | |
| 186 | // hibits += copysign(1.0, sum.hi, sum.lo) | |
| 187 | const uloi = @bitCast(u128, sum.lo); | |
| 188 | uhii += 1 - ((uhii ^ uloi) >> 126); | |
| 189 | sum.hi = @bitCast(f128, uhii); | |
| 190 | } | |
| 191 | } | |
| 192 | return sum.hi; | |
| 193 | } | |
| 194 | ||
| 195 | /// Compute ldexp(a+b, scale) with a single rounding error. It is assumed | |
| 196 | /// that the result will be subnormal, and care is taken to ensure that | |
| 197 | /// double rounding does not occur. | |
| 198 | fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 { | |
| 199 | var sum = dd_add128(a, b); | |
| 200 | // If we are losing at least two bits of accuracy to denormalization, | |
| 201 | // then the first lost bit becomes a round bit, and we adjust the | |
| 202 | // lowest bit of sum.hi to make it a sticky bit summarizing all the | |
| 203 | // bits in sum.lo. With the sticky bit adjusted, the hardware will | |
| 204 | // break any ties in the correct direction. | |
| 205 | // | |
| 206 | // If we are losing only one bit to denormalization, however, we must | |
| 207 | // break the ties manually. | |
| 208 | if (sum.lo != 0) { | |
| 209 | var uhii = @bitCast(u128, sum.hi); | |
| 210 | const bits_lost = -@intCast(i32, (uhii >> 112) & 0x7FFF) - scale + 1; | |
| 211 | if ((bits_lost != 1) == (uhii & 1 != 0)) { | |
| 212 | const uloi = @bitCast(u128, sum.lo); | |
| 213 | uhii += 1 - (((uhii ^ uloi) >> 126) & 2); | |
| 214 | sum.hi = @bitCast(f128, uhii); | |
| 215 | } | |
| 216 | } | |
| 217 | return math.scalbn(sum.hi, scale); | |
| 218 | } | |
| 219 | ||
| 220 | /// Compute a*b exactly, returning the exact result in a struct dd. We assume | |
| 221 | /// that both a and b are normalized, so no underflow or overflow will occur. | |
| 222 | /// The current rounding mode must be round-to-nearest. | |
| 223 | fn dd_mul128(a: f128, b: f128) dd128 { | |
| 224 | var ret: dd128 = undefined; | |
| 225 | const split: f128 = 0x1.0p57 + 1.0; | |
| 226 | ||
| 227 | var p = a * split; | |
| 228 | var ha = a - p; | |
| 229 | ha += p; | |
| 230 | var la = a - ha; | |
| 231 | ||
| 232 | p = b * split; | |
| 233 | var hb = b - p; | |
| 234 | hb += p; | |
| 235 | var lb = b - hb; | |
| 236 | ||
| 237 | p = ha * hb; | |
| 238 | var q = ha * lb + la * hb; | |
| 239 | ||
| 240 | ret.hi = p + q; | |
| 241 | ret.lo = p - ret.hi + q + la * lb; | |
| 242 | return ret; | |
| 243 | } | |
| 244 | ||
| 245 | /// Fused multiply-add: Compute x * y + z with a single rounding error. | |
| 246 | /// | |
| 247 | /// We use scaling to avoid overflow/underflow, along with the | |
| 248 | /// canonical precision-doubling technique adapted from: | |
| 249 | /// | |
| 250 | /// Dekker, T. A Floating-Point Technique for Extending the | |
| 251 | /// Available Precision. Numer. Math. 18, 224-242 (1971). | |
| 252 | fn fma128(x: f128, y: f128, z: f128) f128 { | |
| 253 | if (!math.isFinite(x) or !math.isFinite(y)) { | |
| 254 | return x * y + z; | |
| 255 | } | |
| 256 | if (!math.isFinite(z)) { | |
| 257 | return z; | |
| 258 | } | |
| 259 | if (x == 0.0 or y == 0.0) { | |
| 260 | return x * y + z; | |
| 261 | } | |
| 262 | if (z == 0.0) { | |
| 263 | return x * y; | |
| 264 | } | |
| 265 | ||
| 266 | const x1 = math.frexp(x); | |
| 267 | var ex = x1.exponent; | |
| 268 | var xs = x1.significand; | |
| 269 | const x2 = math.frexp(y); | |
| 270 | var ey = x2.exponent; | |
| 271 | var ys = x2.significand; | |
| 272 | const x3 = math.frexp(z); | |
| 273 | var ez = x3.exponent; | |
| 274 | var zs = x3.significand; | |
| 275 | ||
| 276 | var spread = ex + ey - ez; | |
| 277 | if (spread <= 113 * 2) { | |
| 278 | zs = math.scalbn(zs, -spread); | |
| 279 | } else { | |
| 280 | zs = math.copysign(f128, math.floatMin(f128), zs); | |
| 281 | } | |
| 282 | ||
| 283 | const xy = dd_mul128(xs, ys); | |
| 284 | const r = dd_add128(xy.hi, zs); | |
| 285 | spread = ex + ey; | |
| 286 | ||
| 287 | if (r.hi == 0.0) { | |
| 288 | return xy.hi + zs + math.scalbn(xy.lo, spread); | |
| 289 | } | |
| 290 | ||
| 291 | const adj = add_adjusted128(r.lo, xy.lo); | |
| 292 | if (spread + math.ilogb(r.hi) > -16383) { | |
| 293 | return math.scalbn(r.hi + adj, spread); | |
| 294 | } else { | |
| 295 | return add_and_denorm128(r.hi, adj, spread); | |
| 296 | } | |
| 297 | } | |
| 298 | ||
| 299 | test "type dispatch" { | |
| 300 | try expect(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0)); | |
| 301 | try expect(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0)); | |
| 302 | try expect(fma(f128, 0.0, 1.0, 1.0) == fma128(0.0, 1.0, 1.0)); | |
| 303 | } | |
| 304 | ||
| 305 | test "32" { | |
| 306 | const epsilon = 0.000001; | |
| 307 | ||
| 308 | try expect(math.approxEqAbs(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon)); | |
| 309 | try expect(math.approxEqAbs(f32, fma32(0.2, 5.0, 9.124), 10.124, epsilon)); | |
| 310 | try expect(math.approxEqAbs(f32, fma32(0.8923, 5.0, 9.124), 13.5855, epsilon)); | |
| 311 | try expect(math.approxEqAbs(f32, fma32(1.5, 5.0, 9.124), 16.624, epsilon)); | |
| 312 | try expect(math.approxEqAbs(f32, fma32(37.45, 5.0, 9.124), 196.374004, epsilon)); | |
| 313 | try expect(math.approxEqAbs(f32, fma32(89.123, 5.0, 9.124), 454.739005, epsilon)); | |
| 314 | try expect(math.approxEqAbs(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); | |
| 315 | } | |
| 316 | ||
| 317 | test "64" { | |
| 318 | const epsilon = 0.000001; | |
| 319 | ||
| 320 | try expect(math.approxEqAbs(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon)); | |
| 321 | try expect(math.approxEqAbs(f64, fma64(0.2, 5.0, 9.124), 10.124, epsilon)); | |
| 322 | try expect(math.approxEqAbs(f64, fma64(0.8923, 5.0, 9.124), 13.5855, epsilon)); | |
| 323 | try expect(math.approxEqAbs(f64, fma64(1.5, 5.0, 9.124), 16.624, epsilon)); | |
| 324 | try expect(math.approxEqAbs(f64, fma64(37.45, 5.0, 9.124), 196.374, epsilon)); | |
| 325 | try expect(math.approxEqAbs(f64, fma64(89.123, 5.0, 9.124), 454.739, epsilon)); | |
| 326 | try expect(math.approxEqAbs(f64, fma64(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); | |
| 327 | } | |
| 328 | ||
| 329 | test "128" { | |
| 330 | const epsilon = 0.000001; | |
| 331 | ||
| 332 | try expect(math.approxEqAbs(f128, fma128(0.0, 5.0, 9.124), 9.124, epsilon)); | |
| 333 | try expect(math.approxEqAbs(f128, fma128(0.2, 5.0, 9.124), 10.124, epsilon)); | |
| 334 | try expect(math.approxEqAbs(f128, fma128(0.8923, 5.0, 9.124), 13.5855, epsilon)); | |
| 335 | try expect(math.approxEqAbs(f128, fma128(1.5, 5.0, 9.124), 16.624, epsilon)); | |
| 336 | try expect(math.approxEqAbs(f128, fma128(37.45, 5.0, 9.124), 196.374, epsilon)); | |
| 337 | try expect(math.approxEqAbs(f128, fma128(89.123, 5.0, 9.124), 454.739, epsilon)); | |
| 338 | try expect(math.approxEqAbs(f128, fma128(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); | |
| 339 | } |
lib/std/math/hypot.zig+2-2| ... | ... | @@ -56,7 +56,7 @@ fn hypot32(x: f32, y: f32) f32 { |
| 56 | 56 | yy *= 0x1.0p-90; |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | return z * math.sqrt(@floatCast(f32, @as(f64, x) * x + @as(f64, y) * y)); | |
| 59 | return z * @sqrt(@floatCast(f32, @as(f64, x) * x + @as(f64, y) * y)); | |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | fn sq(hi: *f64, lo: *f64, x: f64) void { |
| ... | ... | @@ -117,7 +117,7 @@ fn hypot64(x: f64, y: f64) f64 { |
| 117 | 117 | sq(&hx, &lx, x); |
| 118 | 118 | sq(&hy, &ly, y); |
| 119 | 119 | |
| 120 | return z * math.sqrt(ly + lx + hy + hx); | |
| 120 | return z * @sqrt(ly + lx + hy + hx); | |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | 123 | test "math.hypot" { |
lib/std/math/ln.zig+8-163| ... | ... | @@ -1,12 +1,6 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/lnf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ln.c | |
| 6 | ||
| 7 | 1 | const std = @import("../std.zig"); |
| 8 | 2 | const math = std.math; |
| 9 | const expect = std.testing.expect; | |
| 3 | const testing = std.testing; | |
| 10 | 4 | |
| 11 | 5 | /// Returns the natural logarithm of x. |
| 12 | 6 | /// |
| ... | ... | @@ -15,175 +9,26 @@ const expect = std.testing.expect; |
| 15 | 9 | /// - ln(0) = -inf |
| 16 | 10 | /// - ln(x) = nan if x < 0 |
| 17 | 11 | /// - ln(nan) = nan |
| 12 | /// TODO remove this in favor of `@log`. | |
| 18 | 13 | pub fn ln(x: anytype) @TypeOf(x) { |
| 19 | 14 | const T = @TypeOf(x); |
| 20 | 15 | switch (@typeInfo(T)) { |
| 21 | 16 | .ComptimeFloat => { |
| 22 | return @as(comptime_float, ln_64(x)); | |
| 23 | }, | |
| 24 | .Float => { | |
| 25 | return switch (T) { | |
| 26 | f32 => ln_32(x), | |
| 27 | f64 => ln_64(x), | |
| 28 | else => @compileError("ln not implemented for " ++ @typeName(T)), | |
| 29 | }; | |
| 17 | return @as(comptime_float, @log(x)); | |
| 30 | 18 | }, |
| 19 | .Float => return @log(x), | |
| 31 | 20 | .ComptimeInt => { |
| 32 | return @as(comptime_int, math.floor(ln_64(@as(f64, x)))); | |
| 21 | return @as(comptime_int, @floor(@log(@as(f64, x)))); | |
| 33 | 22 | }, |
| 34 | 23 | .Int => |IntType| switch (IntType.signedness) { |
| 35 | 24 | .signed => @compileError("ln not implemented for signed integers"), |
| 36 | .unsigned => return @as(T, math.floor(ln_64(@as(f64, x)))), | |
| 25 | .unsigned => return @as(T, @floor(@log(@as(f64, x)))), | |
| 37 | 26 | }, |
| 38 | 27 | else => @compileError("ln not implemented for " ++ @typeName(T)), |
| 39 | 28 | } |
| 40 | 29 | } |
| 41 | 30 | |
| 42 | pub fn ln_32(x_: f32) f32 { | |
| 43 | const ln2_hi: f32 = 6.9313812256e-01; | |
| 44 | const ln2_lo: f32 = 9.0580006145e-06; | |
| 45 | const Lg1: f32 = 0xaaaaaa.0p-24; | |
| 46 | const Lg2: f32 = 0xccce13.0p-25; | |
| 47 | const Lg3: f32 = 0x91e9ee.0p-25; | |
| 48 | const Lg4: f32 = 0xf89e26.0p-26; | |
| 49 | ||
| 50 | var x = x_; | |
| 51 | var ix = @bitCast(u32, x); | |
| 52 | var k: i32 = 0; | |
| 53 | ||
| 54 | // x < 2^(-126) | |
| 55 | if (ix < 0x00800000 or ix >> 31 != 0) { | |
| 56 | // log(+-0) = -inf | |
| 57 | if (ix << 1 == 0) { | |
| 58 | return -math.inf(f32); | |
| 59 | } | |
| 60 | // log(-#) = nan | |
| 61 | if (ix >> 31 != 0) { | |
| 62 | return math.nan(f32); | |
| 63 | } | |
| 64 | ||
| 65 | // subnormal, scale x | |
| 66 | k -= 25; | |
| 67 | x *= 0x1.0p25; | |
| 68 | ix = @bitCast(u32, x); | |
| 69 | } else if (ix >= 0x7F800000) { | |
| 70 | return x; | |
| 71 | } else if (ix == 0x3F800000) { | |
| 72 | return 0; | |
| 73 | } | |
| 74 | ||
| 75 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 76 | ix += 0x3F800000 - 0x3F3504F3; | |
| 77 | k += @intCast(i32, ix >> 23) - 0x7F; | |
| 78 | ix = (ix & 0x007FFFFF) + 0x3F3504F3; | |
| 79 | x = @bitCast(f32, ix); | |
| 80 | ||
| 81 | const f = x - 1.0; | |
| 82 | const s = f / (2.0 + f); | |
| 83 | const z = s * s; | |
| 84 | const w = z * z; | |
| 85 | const t1 = w * (Lg2 + w * Lg4); | |
| 86 | const t2 = z * (Lg1 + w * Lg3); | |
| 87 | const R = t2 + t1; | |
| 88 | const hfsq = 0.5 * f * f; | |
| 89 | const dk = @intToFloat(f32, k); | |
| 90 | ||
| 91 | return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; | |
| 92 | } | |
| 93 | ||
| 94 | pub fn ln_64(x_: f64) f64 { | |
| 95 | const ln2_hi: f64 = 6.93147180369123816490e-01; | |
| 96 | const ln2_lo: f64 = 1.90821492927058770002e-10; | |
| 97 | const Lg1: f64 = 6.666666666666735130e-01; | |
| 98 | const Lg2: f64 = 3.999999999940941908e-01; | |
| 99 | const Lg3: f64 = 2.857142874366239149e-01; | |
| 100 | const Lg4: f64 = 2.222219843214978396e-01; | |
| 101 | const Lg5: f64 = 1.818357216161805012e-01; | |
| 102 | const Lg6: f64 = 1.531383769920937332e-01; | |
| 103 | const Lg7: f64 = 1.479819860511658591e-01; | |
| 104 | ||
| 105 | var x = x_; | |
| 106 | var ix = @bitCast(u64, x); | |
| 107 | var hx = @intCast(u32, ix >> 32); | |
| 108 | var k: i32 = 0; | |
| 109 | ||
| 110 | if (hx < 0x00100000 or hx >> 31 != 0) { | |
| 111 | // log(+-0) = -inf | |
| 112 | if (ix << 1 == 0) { | |
| 113 | return -math.inf(f64); | |
| 114 | } | |
| 115 | // log(-#) = nan | |
| 116 | if (hx >> 31 != 0) { | |
| 117 | return math.nan(f64); | |
| 118 | } | |
| 119 | ||
| 120 | // subnormal, scale x | |
| 121 | k -= 54; | |
| 122 | x *= 0x1.0p54; | |
| 123 | hx = @intCast(u32, @bitCast(u64, ix) >> 32); | |
| 124 | } else if (hx >= 0x7FF00000) { | |
| 125 | return x; | |
| 126 | } else if (hx == 0x3FF00000 and ix << 32 == 0) { | |
| 127 | return 0; | |
| 128 | } | |
| 129 | ||
| 130 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 131 | hx += 0x3FF00000 - 0x3FE6A09E; | |
| 132 | k += @intCast(i32, hx >> 20) - 0x3FF; | |
| 133 | hx = (hx & 0x000FFFFF) + 0x3FE6A09E; | |
| 134 | ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF); | |
| 135 | x = @bitCast(f64, ix); | |
| 136 | ||
| 137 | const f = x - 1.0; | |
| 138 | const hfsq = 0.5 * f * f; | |
| 139 | const s = f / (2.0 + f); | |
| 140 | const z = s * s; | |
| 141 | const w = z * z; | |
| 142 | const t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); | |
| 143 | const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); | |
| 144 | const R = t2 + t1; | |
| 145 | const dk = @intToFloat(f64, k); | |
| 146 | ||
| 147 | return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; | |
| 148 | } | |
| 149 | ||
| 150 | 31 | test "math.ln" { |
| 151 | try expect(ln(@as(f32, 0.2)) == ln_32(0.2)); | |
| 152 | try expect(ln(@as(f64, 0.2)) == ln_64(0.2)); | |
| 153 | } | |
| 154 | ||
| 155 | test "math.ln32" { | |
| 156 | const epsilon = 0.000001; | |
| 157 | ||
| 158 | try expect(math.approxEqAbs(f32, ln_32(0.2), -1.609438, epsilon)); | |
| 159 | try expect(math.approxEqAbs(f32, ln_32(0.8923), -0.113953, epsilon)); | |
| 160 | try expect(math.approxEqAbs(f32, ln_32(1.5), 0.405465, epsilon)); | |
| 161 | try expect(math.approxEqAbs(f32, ln_32(37.45), 3.623007, epsilon)); | |
| 162 | try expect(math.approxEqAbs(f32, ln_32(89.123), 4.490017, epsilon)); | |
| 163 | try expect(math.approxEqAbs(f32, ln_32(123123.234375), 11.720941, epsilon)); | |
| 164 | } | |
| 165 | ||
| 166 | test "math.ln64" { | |
| 167 | const epsilon = 0.000001; | |
| 168 | ||
| 169 | try expect(math.approxEqAbs(f64, ln_64(0.2), -1.609438, epsilon)); | |
| 170 | try expect(math.approxEqAbs(f64, ln_64(0.8923), -0.113953, epsilon)); | |
| 171 | try expect(math.approxEqAbs(f64, ln_64(1.5), 0.405465, epsilon)); | |
| 172 | try expect(math.approxEqAbs(f64, ln_64(37.45), 3.623007, epsilon)); | |
| 173 | try expect(math.approxEqAbs(f64, ln_64(89.123), 4.490017, epsilon)); | |
| 174 | try expect(math.approxEqAbs(f64, ln_64(123123.234375), 11.720941, epsilon)); | |
| 175 | } | |
| 176 | ||
| 177 | test "math.ln32.special" { | |
| 178 | try expect(math.isPositiveInf(ln_32(math.inf(f32)))); | |
| 179 | try expect(math.isNegativeInf(ln_32(0.0))); | |
| 180 | try expect(math.isNan(ln_32(-1.0))); | |
| 181 | try expect(math.isNan(ln_32(math.nan(f32)))); | |
| 182 | } | |
| 183 | ||
| 184 | test "math.ln64.special" { | |
| 185 | try expect(math.isPositiveInf(ln_64(math.inf(f64)))); | |
| 186 | try expect(math.isNegativeInf(ln_64(0.0))); | |
| 187 | try expect(math.isNan(ln_64(-1.0))); | |
| 188 | try expect(math.isNan(ln_64(math.nan(f64)))); | |
| 32 | try testing.expect(ln(@as(f32, 0.2)) == @log(0.2)); | |
| 33 | try testing.expect(ln(@as(f64, 0.2)) == @log(0.2)); | |
| 189 | 34 | } |
lib/std/math/log.zig+6-6| ... | ... | @@ -15,28 +15,28 @@ pub fn log(comptime T: type, base: T, x: T) T { |
| 15 | 15 | } else if (base == 10) { |
| 16 | 16 | return math.log10(x); |
| 17 | 17 | } else if ((@typeInfo(T) == .Float or @typeInfo(T) == .ComptimeFloat) and base == math.e) { |
| 18 | return math.ln(x); | |
| 18 | return @log(x); | |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | const float_base = math.lossyCast(f64, base); |
| 22 | 22 | switch (@typeInfo(T)) { |
| 23 | 23 | .ComptimeFloat => { |
| 24 | return @as(comptime_float, math.ln(@as(f64, x)) / math.ln(float_base)); | |
| 24 | return @as(comptime_float, @log(@as(f64, x)) / @log(float_base)); | |
| 25 | 25 | }, |
| 26 | 26 | .ComptimeInt => { |
| 27 | return @as(comptime_int, math.floor(math.ln(@as(f64, x)) / math.ln(float_base))); | |
| 27 | return @as(comptime_int, @floor(@log(@as(f64, x)) / @log(float_base))); | |
| 28 | 28 | }, |
| 29 | 29 | |
| 30 | 30 | // TODO implement integer log without using float math |
| 31 | 31 | .Int => |IntType| switch (IntType.signedness) { |
| 32 | 32 | .signed => @compileError("log not implemented for signed integers"), |
| 33 | .unsigned => return @floatToInt(T, math.floor(math.ln(@intToFloat(f64, x)) / math.ln(float_base))), | |
| 33 | .unsigned => return @floatToInt(T, @floor(@log(@intToFloat(f64, x)) / @log(float_base))), | |
| 34 | 34 | }, |
| 35 | 35 | |
| 36 | 36 | .Float => { |
| 37 | 37 | switch (T) { |
| 38 | f32 => return @floatCast(f32, math.ln(@as(f64, x)) / math.ln(float_base)), | |
| 39 | f64 => return math.ln(x) / math.ln(float_base), | |
| 38 | f32 => return @floatCast(f32, @log(@as(f64, x)) / @log(float_base)), | |
| 39 | f64 => return @log(x) / @log(float_base), | |
| 40 | 40 | else => @compileError("log not implemented for " ++ @typeName(T)), |
| 41 | 41 | } |
| 42 | 42 | }, |
lib/std/math/log10.zig+4-192| ... | ... | @@ -1,9 +1,3 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log10f.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log10.c | |
| 6 | ||
| 7 | 1 | const std = @import("../std.zig"); |
| 8 | 2 | const math = std.math; |
| 9 | 3 | const testing = std.testing; |
| ... | ... | @@ -20,198 +14,16 @@ pub fn log10(x: anytype) @TypeOf(x) { |
| 20 | 14 | const T = @TypeOf(x); |
| 21 | 15 | switch (@typeInfo(T)) { |
| 22 | 16 | .ComptimeFloat => { |
| 23 | return @as(comptime_float, log10_64(x)); | |
| 24 | }, | |
| 25 | .Float => { | |
| 26 | return switch (T) { | |
| 27 | f32 => log10_32(x), | |
| 28 | f64 => log10_64(x), | |
| 29 | else => @compileError("log10 not implemented for " ++ @typeName(T)), | |
| 30 | }; | |
| 17 | return @as(comptime_float, @log10(x)); | |
| 31 | 18 | }, |
| 19 | .Float => return @log10(x), | |
| 32 | 20 | .ComptimeInt => { |
| 33 | return @as(comptime_int, math.floor(log10_64(@as(f64, x)))); | |
| 21 | return @as(comptime_int, @floor(@log10(@as(f64, x)))); | |
| 34 | 22 | }, |
| 35 | 23 | .Int => |IntType| switch (IntType.signedness) { |
| 36 | 24 | .signed => @compileError("log10 not implemented for signed integers"), |
| 37 | .unsigned => return @floatToInt(T, math.floor(log10_64(@intToFloat(f64, x)))), | |
| 25 | .unsigned => return @floatToInt(T, @floor(@log10(@intToFloat(f64, x)))), | |
| 38 | 26 | }, |
| 39 | 27 | else => @compileError("log10 not implemented for " ++ @typeName(T)), |
| 40 | 28 | } |
| 41 | 29 | } |
| 42 | ||
| 43 | pub fn log10_32(x_: f32) f32 { | |
| 44 | const ivln10hi: f32 = 4.3432617188e-01; | |
| 45 | const ivln10lo: f32 = -3.1689971365e-05; | |
| 46 | const log10_2hi: f32 = 3.0102920532e-01; | |
| 47 | const log10_2lo: f32 = 7.9034151668e-07; | |
| 48 | const Lg1: f32 = 0xaaaaaa.0p-24; | |
| 49 | const Lg2: f32 = 0xccce13.0p-25; | |
| 50 | const Lg3: f32 = 0x91e9ee.0p-25; | |
| 51 | const Lg4: f32 = 0xf89e26.0p-26; | |
| 52 | ||
| 53 | var x = x_; | |
| 54 | var u = @bitCast(u32, x); | |
| 55 | var ix = u; | |
| 56 | var k: i32 = 0; | |
| 57 | ||
| 58 | // x < 2^(-126) | |
| 59 | if (ix < 0x00800000 or ix >> 31 != 0) { | |
| 60 | // log(+-0) = -inf | |
| 61 | if (ix << 1 == 0) { | |
| 62 | return -math.inf(f32); | |
| 63 | } | |
| 64 | // log(-#) = nan | |
| 65 | if (ix >> 31 != 0) { | |
| 66 | return math.nan(f32); | |
| 67 | } | |
| 68 | ||
| 69 | k -= 25; | |
| 70 | x *= 0x1.0p25; | |
| 71 | ix = @bitCast(u32, x); | |
| 72 | } else if (ix >= 0x7F800000) { | |
| 73 | return x; | |
| 74 | } else if (ix == 0x3F800000) { | |
| 75 | return 0; | |
| 76 | } | |
| 77 | ||
| 78 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 79 | ix += 0x3F800000 - 0x3F3504F3; | |
| 80 | k += @intCast(i32, ix >> 23) - 0x7F; | |
| 81 | ix = (ix & 0x007FFFFF) + 0x3F3504F3; | |
| 82 | x = @bitCast(f32, ix); | |
| 83 | ||
| 84 | const f = x - 1.0; | |
| 85 | const s = f / (2.0 + f); | |
| 86 | const z = s * s; | |
| 87 | const w = z * z; | |
| 88 | const t1 = w * (Lg2 + w * Lg4); | |
| 89 | const t2 = z * (Lg1 + w * Lg3); | |
| 90 | const R = t2 + t1; | |
| 91 | const hfsq = 0.5 * f * f; | |
| 92 | ||
| 93 | var hi = f - hfsq; | |
| 94 | u = @bitCast(u32, hi); | |
| 95 | u &= 0xFFFFF000; | |
| 96 | hi = @bitCast(f32, u); | |
| 97 | const lo = f - hi - hfsq + s * (hfsq + R); | |
| 98 | const dk = @intToFloat(f32, k); | |
| 99 | ||
| 100 | return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi; | |
| 101 | } | |
| 102 | ||
| 103 | pub fn log10_64(x_: f64) f64 { | |
| 104 | const ivln10hi: f64 = 4.34294481878168880939e-01; | |
| 105 | const ivln10lo: f64 = 2.50829467116452752298e-11; | |
| 106 | const log10_2hi: f64 = 3.01029995663611771306e-01; | |
| 107 | const log10_2lo: f64 = 3.69423907715893078616e-13; | |
| 108 | const Lg1: f64 = 6.666666666666735130e-01; | |
| 109 | const Lg2: f64 = 3.999999999940941908e-01; | |
| 110 | const Lg3: f64 = 2.857142874366239149e-01; | |
| 111 | const Lg4: f64 = 2.222219843214978396e-01; | |
| 112 | const Lg5: f64 = 1.818357216161805012e-01; | |
| 113 | const Lg6: f64 = 1.531383769920937332e-01; | |
| 114 | const Lg7: f64 = 1.479819860511658591e-01; | |
| 115 | ||
| 116 | var x = x_; | |
| 117 | var ix = @bitCast(u64, x); | |
| 118 | var hx = @intCast(u32, ix >> 32); | |
| 119 | var k: i32 = 0; | |
| 120 | ||
| 121 | if (hx < 0x00100000 or hx >> 31 != 0) { | |
| 122 | // log(+-0) = -inf | |
| 123 | if (ix << 1 == 0) { | |
| 124 | return -math.inf(f32); | |
| 125 | } | |
| 126 | // log(-#) = nan | |
| 127 | if (hx >> 31 != 0) { | |
| 128 | return math.nan(f32); | |
| 129 | } | |
| 130 | ||
| 131 | // subnormal, scale x | |
| 132 | k -= 54; | |
| 133 | x *= 0x1.0p54; | |
| 134 | hx = @intCast(u32, @bitCast(u64, x) >> 32); | |
| 135 | } else if (hx >= 0x7FF00000) { | |
| 136 | return x; | |
| 137 | } else if (hx == 0x3FF00000 and ix << 32 == 0) { | |
| 138 | return 0; | |
| 139 | } | |
| 140 | ||
| 141 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 142 | hx += 0x3FF00000 - 0x3FE6A09E; | |
| 143 | k += @intCast(i32, hx >> 20) - 0x3FF; | |
| 144 | hx = (hx & 0x000FFFFF) + 0x3FE6A09E; | |
| 145 | ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF); | |
| 146 | x = @bitCast(f64, ix); | |
| 147 | ||
| 148 | const f = x - 1.0; | |
| 149 | const hfsq = 0.5 * f * f; | |
| 150 | const s = f / (2.0 + f); | |
| 151 | const z = s * s; | |
| 152 | const w = z * z; | |
| 153 | const t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); | |
| 154 | const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); | |
| 155 | const R = t2 + t1; | |
| 156 | ||
| 157 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) | |
| 158 | var hi = f - hfsq; | |
| 159 | var hii = @bitCast(u64, hi); | |
| 160 | hii &= @as(u64, maxInt(u64)) << 32; | |
| 161 | hi = @bitCast(f64, hii); | |
| 162 | const lo = f - hi - hfsq + s * (hfsq + R); | |
| 163 | ||
| 164 | // val_hi + val_lo ~ log10(1 + f) + k * log10(2) | |
| 165 | var val_hi = hi * ivln10hi; | |
| 166 | const dk = @intToFloat(f64, k); | |
| 167 | const y = dk * log10_2hi; | |
| 168 | var val_lo = dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi; | |
| 169 | ||
| 170 | // Extra precision multiplication | |
| 171 | const ww = y + val_hi; | |
| 172 | val_lo += (y - ww) + val_hi; | |
| 173 | val_hi = ww; | |
| 174 | ||
| 175 | return val_lo + val_hi; | |
| 176 | } | |
| 177 | ||
| 178 | test "math.log10" { | |
| 179 | try testing.expect(log10(@as(f32, 0.2)) == log10_32(0.2)); | |
| 180 | try testing.expect(log10(@as(f64, 0.2)) == log10_64(0.2)); | |
| 181 | } | |
| 182 | ||
| 183 | test "math.log10_32" { | |
| 184 | const epsilon = 0.000001; | |
| 185 | ||
| 186 | try testing.expect(math.approxEqAbs(f32, log10_32(0.2), -0.698970, epsilon)); | |
| 187 | try testing.expect(math.approxEqAbs(f32, log10_32(0.8923), -0.049489, epsilon)); | |
| 188 | try testing.expect(math.approxEqAbs(f32, log10_32(1.5), 0.176091, epsilon)); | |
| 189 | try testing.expect(math.approxEqAbs(f32, log10_32(37.45), 1.573452, epsilon)); | |
| 190 | try testing.expect(math.approxEqAbs(f32, log10_32(89.123), 1.94999, epsilon)); | |
| 191 | try testing.expect(math.approxEqAbs(f32, log10_32(123123.234375), 5.09034, epsilon)); | |
| 192 | } | |
| 193 | ||
| 194 | test "math.log10_64" { | |
| 195 | const epsilon = 0.000001; | |
| 196 | ||
| 197 | try testing.expect(math.approxEqAbs(f64, log10_64(0.2), -0.698970, epsilon)); | |
| 198 | try testing.expect(math.approxEqAbs(f64, log10_64(0.8923), -0.049489, epsilon)); | |
| 199 | try testing.expect(math.approxEqAbs(f64, log10_64(1.5), 0.176091, epsilon)); | |
| 200 | try testing.expect(math.approxEqAbs(f64, log10_64(37.45), 1.573452, epsilon)); | |
| 201 | try testing.expect(math.approxEqAbs(f64, log10_64(89.123), 1.94999, epsilon)); | |
| 202 | try testing.expect(math.approxEqAbs(f64, log10_64(123123.234375), 5.09034, epsilon)); | |
| 203 | } | |
| 204 | ||
| 205 | test "math.log10_32.special" { | |
| 206 | try testing.expect(math.isPositiveInf(log10_32(math.inf(f32)))); | |
| 207 | try testing.expect(math.isNegativeInf(log10_32(0.0))); | |
| 208 | try testing.expect(math.isNan(log10_32(-1.0))); | |
| 209 | try testing.expect(math.isNan(log10_32(math.nan(f32)))); | |
| 210 | } | |
| 211 | ||
| 212 | test "math.log10_64.special" { | |
| 213 | try testing.expect(math.isPositiveInf(log10_64(math.inf(f64)))); | |
| 214 | try testing.expect(math.isNegativeInf(log10_64(0.0))); | |
| 215 | try testing.expect(math.isNan(log10_64(-1.0))); | |
| 216 | try testing.expect(math.isNan(log10_64(math.nan(f64)))); | |
| 217 | } |
lib/std/math/log2.zig+5-179| ... | ... | @@ -1,13 +1,6 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log2f.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log2.c | |
| 6 | ||
| 7 | 1 | const std = @import("../std.zig"); |
| 8 | 2 | const math = std.math; |
| 9 | 3 | const expect = std.testing.expect; |
| 10 | const maxInt = std.math.maxInt; | |
| 11 | 4 | |
| 12 | 5 | /// Returns the base-2 logarithm of x. |
| 13 | 6 | /// |
| ... | ... | @@ -20,15 +13,9 @@ pub fn log2(x: anytype) @TypeOf(x) { |
| 20 | 13 | const T = @TypeOf(x); |
| 21 | 14 | switch (@typeInfo(T)) { |
| 22 | 15 | .ComptimeFloat => { |
| 23 | return @as(comptime_float, log2_64(x)); | |
| 24 | }, | |
| 25 | .Float => { | |
| 26 | return switch (T) { | |
| 27 | f32 => log2_32(x), | |
| 28 | f64 => log2_64(x), | |
| 29 | else => @compileError("log2 not implemented for " ++ @typeName(T)), | |
| 30 | }; | |
| 16 | return @as(comptime_float, @log2(x)); | |
| 31 | 17 | }, |
| 18 | .Float => return @log2(x), | |
| 32 | 19 | .ComptimeInt => comptime { |
| 33 | 20 | var result = 0; |
| 34 | 21 | var x_shifted = x; |
| ... | ... | @@ -46,168 +33,7 @@ pub fn log2(x: anytype) @TypeOf(x) { |
| 46 | 33 | } |
| 47 | 34 | } |
| 48 | 35 | |
| 49 | pub fn log2_32(x_: f32) f32 { | |
| 50 | const ivln2hi: f32 = 1.4428710938e+00; | |
| 51 | const ivln2lo: f32 = -1.7605285393e-04; | |
| 52 | const Lg1: f32 = 0xaaaaaa.0p-24; | |
| 53 | const Lg2: f32 = 0xccce13.0p-25; | |
| 54 | const Lg3: f32 = 0x91e9ee.0p-25; | |
| 55 | const Lg4: f32 = 0xf89e26.0p-26; | |
| 56 | ||
| 57 | var x = x_; | |
| 58 | var u = @bitCast(u32, x); | |
| 59 | var ix = u; | |
| 60 | var k: i32 = 0; | |
| 61 | ||
| 62 | // x < 2^(-126) | |
| 63 | if (ix < 0x00800000 or ix >> 31 != 0) { | |
| 64 | // log(+-0) = -inf | |
| 65 | if (ix << 1 == 0) { | |
| 66 | return -math.inf(f32); | |
| 67 | } | |
| 68 | // log(-#) = nan | |
| 69 | if (ix >> 31 != 0) { | |
| 70 | return math.nan(f32); | |
| 71 | } | |
| 72 | ||
| 73 | k -= 25; | |
| 74 | x *= 0x1.0p25; | |
| 75 | ix = @bitCast(u32, x); | |
| 76 | } else if (ix >= 0x7F800000) { | |
| 77 | return x; | |
| 78 | } else if (ix == 0x3F800000) { | |
| 79 | return 0; | |
| 80 | } | |
| 81 | ||
| 82 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 83 | ix += 0x3F800000 - 0x3F3504F3; | |
| 84 | k += @intCast(i32, ix >> 23) - 0x7F; | |
| 85 | ix = (ix & 0x007FFFFF) + 0x3F3504F3; | |
| 86 | x = @bitCast(f32, ix); | |
| 87 | ||
| 88 | const f = x - 1.0; | |
| 89 | const s = f / (2.0 + f); | |
| 90 | const z = s * s; | |
| 91 | const w = z * z; | |
| 92 | const t1 = w * (Lg2 + w * Lg4); | |
| 93 | const t2 = z * (Lg1 + w * Lg3); | |
| 94 | const R = t2 + t1; | |
| 95 | const hfsq = 0.5 * f * f; | |
| 96 | ||
| 97 | var hi = f - hfsq; | |
| 98 | u = @bitCast(u32, hi); | |
| 99 | u &= 0xFFFFF000; | |
| 100 | hi = @bitCast(f32, u); | |
| 101 | const lo = f - hi - hfsq + s * (hfsq + R); | |
| 102 | return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + @intToFloat(f32, k); | |
| 103 | } | |
| 104 | ||
| 105 | pub fn log2_64(x_: f64) f64 { | |
| 106 | const ivln2hi: f64 = 1.44269504072144627571e+00; | |
| 107 | const ivln2lo: f64 = 1.67517131648865118353e-10; | |
| 108 | const Lg1: f64 = 6.666666666666735130e-01; | |
| 109 | const Lg2: f64 = 3.999999999940941908e-01; | |
| 110 | const Lg3: f64 = 2.857142874366239149e-01; | |
| 111 | const Lg4: f64 = 2.222219843214978396e-01; | |
| 112 | const Lg5: f64 = 1.818357216161805012e-01; | |
| 113 | const Lg6: f64 = 1.531383769920937332e-01; | |
| 114 | const Lg7: f64 = 1.479819860511658591e-01; | |
| 115 | ||
| 116 | var x = x_; | |
| 117 | var ix = @bitCast(u64, x); | |
| 118 | var hx = @intCast(u32, ix >> 32); | |
| 119 | var k: i32 = 0; | |
| 120 | ||
| 121 | if (hx < 0x00100000 or hx >> 31 != 0) { | |
| 122 | // log(+-0) = -inf | |
| 123 | if (ix << 1 == 0) { | |
| 124 | return -math.inf(f64); | |
| 125 | } | |
| 126 | // log(-#) = nan | |
| 127 | if (hx >> 31 != 0) { | |
| 128 | return math.nan(f64); | |
| 129 | } | |
| 130 | ||
| 131 | // subnormal, scale x | |
| 132 | k -= 54; | |
| 133 | x *= 0x1.0p54; | |
| 134 | hx = @intCast(u32, @bitCast(u64, x) >> 32); | |
| 135 | } else if (hx >= 0x7FF00000) { | |
| 136 | return x; | |
| 137 | } else if (hx == 0x3FF00000 and ix << 32 == 0) { | |
| 138 | return 0; | |
| 139 | } | |
| 140 | ||
| 141 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 142 | hx += 0x3FF00000 - 0x3FE6A09E; | |
| 143 | k += @intCast(i32, hx >> 20) - 0x3FF; | |
| 144 | hx = (hx & 0x000FFFFF) + 0x3FE6A09E; | |
| 145 | ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF); | |
| 146 | x = @bitCast(f64, ix); | |
| 147 | ||
| 148 | const f = x - 1.0; | |
| 149 | const hfsq = 0.5 * f * f; | |
| 150 | const s = f / (2.0 + f); | |
| 151 | const z = s * s; | |
| 152 | const w = z * z; | |
| 153 | const t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); | |
| 154 | const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); | |
| 155 | const R = t2 + t1; | |
| 156 | ||
| 157 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) | |
| 158 | var hi = f - hfsq; | |
| 159 | var hii = @bitCast(u64, hi); | |
| 160 | hii &= @as(u64, maxInt(u64)) << 32; | |
| 161 | hi = @bitCast(f64, hii); | |
| 162 | const lo = f - hi - hfsq + s * (hfsq + R); | |
| 163 | ||
| 164 | var val_hi = hi * ivln2hi; | |
| 165 | var val_lo = (lo + hi) * ivln2lo + lo * ivln2hi; | |
| 166 | ||
| 167 | // spadd(val_hi, val_lo, y) | |
| 168 | const y = @intToFloat(f64, k); | |
| 169 | const ww = y + val_hi; | |
| 170 | val_lo += (y - ww) + val_hi; | |
| 171 | val_hi = ww; | |
| 172 | ||
| 173 | return val_lo + val_hi; | |
| 174 | } | |
| 175 | ||
| 176 | test "math.log2" { | |
| 177 | try expect(log2(@as(f32, 0.2)) == log2_32(0.2)); | |
| 178 | try expect(log2(@as(f64, 0.2)) == log2_64(0.2)); | |
| 179 | } | |
| 180 | ||
| 181 | test "math.log2_32" { | |
| 182 | const epsilon = 0.000001; | |
| 183 | ||
| 184 | try expect(math.approxEqAbs(f32, log2_32(0.2), -2.321928, epsilon)); | |
| 185 | try expect(math.approxEqAbs(f32, log2_32(0.8923), -0.164399, epsilon)); | |
| 186 | try expect(math.approxEqAbs(f32, log2_32(1.5), 0.584962, epsilon)); | |
| 187 | try expect(math.approxEqAbs(f32, log2_32(37.45), 5.226894, epsilon)); | |
| 188 | try expect(math.approxEqAbs(f32, log2_32(123123.234375), 16.909744, epsilon)); | |
| 189 | } | |
| 190 | ||
| 191 | test "math.log2_64" { | |
| 192 | const epsilon = 0.000001; | |
| 193 | ||
| 194 | try expect(math.approxEqAbs(f64, log2_64(0.2), -2.321928, epsilon)); | |
| 195 | try expect(math.approxEqAbs(f64, log2_64(0.8923), -0.164399, epsilon)); | |
| 196 | try expect(math.approxEqAbs(f64, log2_64(1.5), 0.584962, epsilon)); | |
| 197 | try expect(math.approxEqAbs(f64, log2_64(37.45), 5.226894, epsilon)); | |
| 198 | try expect(math.approxEqAbs(f64, log2_64(123123.234375), 16.909744, epsilon)); | |
| 199 | } | |
| 200 | ||
| 201 | test "math.log2_32.special" { | |
| 202 | try expect(math.isPositiveInf(log2_32(math.inf(f32)))); | |
| 203 | try expect(math.isNegativeInf(log2_32(0.0))); | |
| 204 | try expect(math.isNan(log2_32(-1.0))); | |
| 205 | try expect(math.isNan(log2_32(math.nan(f32)))); | |
| 206 | } | |
| 207 | ||
| 208 | test "math.log2_64.special" { | |
| 209 | try expect(math.isPositiveInf(log2_64(math.inf(f64)))); | |
| 210 | try expect(math.isNegativeInf(log2_64(0.0))); | |
| 211 | try expect(math.isNan(log2_64(-1.0))); | |
| 212 | try expect(math.isNan(log2_64(math.nan(f64)))); | |
| 36 | test "log2" { | |
| 37 | try expect(log2(@as(f32, 0.2)) == @log2(0.2)); | |
| 38 | try expect(log2(@as(f64, 0.2)) == @log2(0.2)); | |
| 213 | 39 | } |
lib/std/math/nan.zig+14-14| ... | ... | @@ -2,13 +2,13 @@ const math = @import("../math.zig"); |
| 2 | 2 | |
| 3 | 3 | /// Returns the nan representation for type T. |
| 4 | 4 | pub fn nan(comptime T: type) T { |
| 5 | return switch (T) { | |
| 6 | f16 => math.nan_f16, | |
| 7 | f32 => math.nan_f32, | |
| 8 | f64 => math.nan_f64, | |
| 9 | f80 => math.nan_f80, | |
| 10 | f128 => math.nan_f128, | |
| 11 | else => @compileError("nan not implemented for " ++ @typeName(T)), | |
| 5 | return switch (@typeInfo(T).Float.bits) { | |
| 6 | 16 => math.nan_f16, | |
| 7 | 32 => math.nan_f32, | |
| 8 | 64 => math.nan_f64, | |
| 9 | 80 => math.nan_f80, | |
| 10 | 128 => math.nan_f128, | |
| 11 | else => @compileError("unreachable"), | |
| 12 | 12 | }; |
| 13 | 13 | } |
| 14 | 14 | |
| ... | ... | @@ -16,12 +16,12 @@ pub fn nan(comptime T: type) T { |
| 16 | 16 | pub fn snan(comptime T: type) T { |
| 17 | 17 | // Note: A signalling nan is identical to a standard right now by may have a different bit |
| 18 | 18 | // representation in the future when required. |
| 19 | return switch (T) { | |
| 20 | f16 => @bitCast(f16, math.nan_u16), | |
| 21 | f32 => @bitCast(f32, math.nan_u32), | |
| 22 | f64 => @bitCast(f64, math.nan_u64), | |
| 23 | f80 => @bitCast(f80, math.nan_u80), | |
| 24 | f128 => @bitCast(f128, math.nan_u128), | |
| 25 | else => @compileError("snan not implemented for " ++ @typeName(T)), | |
| 19 | return switch (@typeInfo(T).Float.bits) { | |
| 20 | 16 => math.nan_u16, | |
| 21 | 32 => math.nan_u32, | |
| 22 | 64 => math.nan_u64, | |
| 23 | 80 => math.nan_u80, | |
| 24 | 128 => math.nan_u128, | |
| 25 | else => @compileError("unreachable"), | |
| 26 | 26 | }; |
| 27 | 27 | } |
lib/std/math/pow.zig+6-6| ... | ... | @@ -82,7 +82,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 82 | 82 | } |
| 83 | 83 | // pow(x, +inf) = +0 for |x| < 1 |
| 84 | 84 | // pow(x, -inf) = +0 for |x| > 1 |
| 85 | else if ((math.fabs(x) < 1) == math.isPositiveInf(y)) { | |
| 85 | else if ((@fabs(x) < 1) == math.isPositiveInf(y)) { | |
| 86 | 86 | return 0; |
| 87 | 87 | } |
| 88 | 88 | // pow(x, -inf) = +inf for |x| < 1 |
| ... | ... | @@ -108,14 +108,14 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 108 | 108 | |
| 109 | 109 | // special case sqrt |
| 110 | 110 | if (y == 0.5) { |
| 111 | return math.sqrt(x); | |
| 111 | return @sqrt(x); | |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | 114 | if (y == -0.5) { |
| 115 | return 1 / math.sqrt(x); | |
| 115 | return 1 / @sqrt(x); | |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | const r1 = math.modf(math.fabs(y)); | |
| 118 | const r1 = math.modf(@fabs(y)); | |
| 119 | 119 | var yi = r1.ipart; |
| 120 | 120 | var yf = r1.fpart; |
| 121 | 121 | |
| ... | ... | @@ -123,7 +123,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 123 | 123 | return math.nan(T); |
| 124 | 124 | } |
| 125 | 125 | if (yi >= 1 << (@typeInfo(T).Float.bits - 1)) { |
| 126 | return math.exp(y * math.ln(x)); | |
| 126 | return @exp(y * @log(x)); | |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | 129 | // a = a1 * 2^ae |
| ... | ... | @@ -136,7 +136,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 136 | 136 | yf -= 1; |
| 137 | 137 | yi += 1; |
| 138 | 138 | } |
| 139 | a1 = math.exp(yf * math.ln(x)); | |
| 139 | a1 = @exp(yf * @log(x)); | |
| 140 | 140 | } |
| 141 | 141 | |
| 142 | 142 | // a *= x^yi |
lib/std/math/round.zig deleted-185| ... | ... | @@ -1,185 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/roundf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/round.c | |
| 6 | ||
| 7 | const expect = std.testing.expect; | |
| 8 | const std = @import("../std.zig"); | |
| 9 | const math = std.math; | |
| 10 | ||
| 11 | /// Returns x rounded to the nearest integer, rounding half away from zero. | |
| 12 | /// | |
| 13 | /// Special Cases: | |
| 14 | /// - round(+-0) = +-0 | |
| 15 | /// - round(+-inf) = +-inf | |
| 16 | /// - round(nan) = nan | |
| 17 | pub fn round(x: anytype) @TypeOf(x) { | |
| 18 | const T = @TypeOf(x); | |
| 19 | return switch (T) { | |
| 20 | f32 => round32(x), | |
| 21 | f64 => round64(x), | |
| 22 | f128 => round128(x), | |
| 23 | ||
| 24 | // TODO this is not correct for some targets | |
| 25 | c_longdouble => @floatCast(c_longdouble, round128(x)), | |
| 26 | ||
| 27 | else => @compileError("round not implemented for " ++ @typeName(T)), | |
| 28 | }; | |
| 29 | } | |
| 30 | ||
| 31 | fn round32(x_: f32) f32 { | |
| 32 | const f32_toint = 1.0 / math.floatEps(f32); | |
| 33 | ||
| 34 | var x = x_; | |
| 35 | const u = @bitCast(u32, x); | |
| 36 | const e = (u >> 23) & 0xFF; | |
| 37 | var y: f32 = undefined; | |
| 38 | ||
| 39 | if (e >= 0x7F + 23) { | |
| 40 | return x; | |
| 41 | } | |
| 42 | if (u >> 31 != 0) { | |
| 43 | x = -x; | |
| 44 | } | |
| 45 | if (e < 0x7F - 1) { | |
| 46 | math.doNotOptimizeAway(x + f32_toint); | |
| 47 | return 0 * @bitCast(f32, u); | |
| 48 | } | |
| 49 | ||
| 50 | y = x + f32_toint - f32_toint - x; | |
| 51 | if (y > 0.5) { | |
| 52 | y = y + x - 1; | |
| 53 | } else if (y <= -0.5) { | |
| 54 | y = y + x + 1; | |
| 55 | } else { | |
| 56 | y = y + x; | |
| 57 | } | |
| 58 | ||
| 59 | if (u >> 31 != 0) { | |
| 60 | return -y; | |
| 61 | } else { | |
| 62 | return y; | |
| 63 | } | |
| 64 | } | |
| 65 | ||
| 66 | fn round64(x_: f64) f64 { | |
| 67 | const f64_toint = 1.0 / math.floatEps(f64); | |
| 68 | ||
| 69 | var x = x_; | |
| 70 | const u = @bitCast(u64, x); | |
| 71 | const e = (u >> 52) & 0x7FF; | |
| 72 | var y: f64 = undefined; | |
| 73 | ||
| 74 | if (e >= 0x3FF + 52) { | |
| 75 | return x; | |
| 76 | } | |
| 77 | if (u >> 63 != 0) { | |
| 78 | x = -x; | |
| 79 | } | |
| 80 | if (e < 0x3ff - 1) { | |
| 81 | math.doNotOptimizeAway(x + f64_toint); | |
| 82 | return 0 * @bitCast(f64, u); | |
| 83 | } | |
| 84 | ||
| 85 | y = x + f64_toint - f64_toint - x; | |
| 86 | if (y > 0.5) { | |
| 87 | y = y + x - 1; | |
| 88 | } else if (y <= -0.5) { | |
| 89 | y = y + x + 1; | |
| 90 | } else { | |
| 91 | y = y + x; | |
| 92 | } | |
| 93 | ||
| 94 | if (u >> 63 != 0) { | |
| 95 | return -y; | |
| 96 | } else { | |
| 97 | return y; | |
| 98 | } | |
| 99 | } | |
| 100 | ||
| 101 | fn round128(x_: f128) f128 { | |
| 102 | const f128_toint = 1.0 / math.floatEps(f128); | |
| 103 | ||
| 104 | var x = x_; | |
| 105 | const u = @bitCast(u128, x); | |
| 106 | const e = (u >> 112) & 0x7FFF; | |
| 107 | var y: f128 = undefined; | |
| 108 | ||
| 109 | if (e >= 0x3FFF + 112) { | |
| 110 | return x; | |
| 111 | } | |
| 112 | if (u >> 127 != 0) { | |
| 113 | x = -x; | |
| 114 | } | |
| 115 | if (e < 0x3FFF - 1) { | |
| 116 | math.doNotOptimizeAway(x + f128_toint); | |
| 117 | return 0 * @bitCast(f128, u); | |
| 118 | } | |
| 119 | ||
| 120 | y = x + f128_toint - f128_toint - x; | |
| 121 | if (y > 0.5) { | |
| 122 | y = y + x - 1; | |
| 123 | } else if (y <= -0.5) { | |
| 124 | y = y + x + 1; | |
| 125 | } else { | |
| 126 | y = y + x; | |
| 127 | } | |
| 128 | ||
| 129 | if (u >> 127 != 0) { | |
| 130 | return -y; | |
| 131 | } else { | |
| 132 | return y; | |
| 133 | } | |
| 134 | } | |
| 135 | ||
| 136 | test "math.round" { | |
| 137 | try expect(round(@as(f32, 1.3)) == round32(1.3)); | |
| 138 | try expect(round(@as(f64, 1.3)) == round64(1.3)); | |
| 139 | try expect(round(@as(f128, 1.3)) == round128(1.3)); | |
| 140 | } | |
| 141 | ||
| 142 | test "math.round32" { | |
| 143 | try expect(round32(1.3) == 1.0); | |
| 144 | try expect(round32(-1.3) == -1.0); | |
| 145 | try expect(round32(0.2) == 0.0); | |
| 146 | try expect(round32(1.8) == 2.0); | |
| 147 | } | |
| 148 | ||
| 149 | test "math.round64" { | |
| 150 | try expect(round64(1.3) == 1.0); | |
| 151 | try expect(round64(-1.3) == -1.0); | |
| 152 | try expect(round64(0.2) == 0.0); | |
| 153 | try expect(round64(1.8) == 2.0); | |
| 154 | } | |
| 155 | ||
| 156 | test "math.round128" { | |
| 157 | try expect(round128(1.3) == 1.0); | |
| 158 | try expect(round128(-1.3) == -1.0); | |
| 159 | try expect(round128(0.2) == 0.0); | |
| 160 | try expect(round128(1.8) == 2.0); | |
| 161 | } | |
| 162 | ||
| 163 | test "math.round32.special" { | |
| 164 | try expect(round32(0.0) == 0.0); | |
| 165 | try expect(round32(-0.0) == -0.0); | |
| 166 | try expect(math.isPositiveInf(round32(math.inf(f32)))); | |
| 167 | try expect(math.isNegativeInf(round32(-math.inf(f32)))); | |
| 168 | try expect(math.isNan(round32(math.nan(f32)))); | |
| 169 | } | |
| 170 | ||
| 171 | test "math.round64.special" { | |
| 172 | try expect(round64(0.0) == 0.0); | |
| 173 | try expect(round64(-0.0) == -0.0); | |
| 174 | try expect(math.isPositiveInf(round64(math.inf(f64)))); | |
| 175 | try expect(math.isNegativeInf(round64(-math.inf(f64)))); | |
| 176 | try expect(math.isNan(round64(math.nan(f64)))); | |
| 177 | } | |
| 178 | ||
| 179 | test "math.round128.special" { | |
| 180 | try expect(round128(0.0) == 0.0); | |
| 181 | try expect(round128(-0.0) == -0.0); | |
| 182 | try expect(math.isPositiveInf(round128(math.inf(f128)))); | |
| 183 | try expect(math.isNegativeInf(round128(-math.inf(f128)))); | |
| 184 | try expect(math.isNan(round128(math.nan(f128)))); | |
| 185 | } |
lib/std/math/sin.zig deleted-168| ... | ... | @@ -1,168 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/sinf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/sin.c | |
| 6 | // | |
| 7 | const std = @import("../std.zig"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | const kernel = @import("__trig.zig"); | |
| 12 | const __rem_pio2 = @import("__rem_pio2.zig").__rem_pio2; | |
| 13 | const __rem_pio2f = @import("__rem_pio2f.zig").__rem_pio2f; | |
| 14 | ||
| 15 | /// Returns the sine of the radian value x. | |
| 16 | /// | |
| 17 | /// Special Cases: | |
| 18 | /// - sin(+-0) = +-0 | |
| 19 | /// - sin(+-inf) = nan | |
| 20 | /// - sin(nan) = nan | |
| 21 | pub fn sin(x: anytype) @TypeOf(x) { | |
| 22 | const T = @TypeOf(x); | |
| 23 | return switch (T) { | |
| 24 | f32 => sin32(x), | |
| 25 | f64 => sin64(x), | |
| 26 | else => @compileError("sin not implemented for " ++ @typeName(T)), | |
| 27 | }; | |
| 28 | } | |
| 29 | ||
| 30 | fn sin32(x: f32) f32 { | |
| 31 | // Small multiples of pi/2 rounded to double precision. | |
| 32 | const s1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 | |
| 33 | const s2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 | |
| 34 | const s3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2 | |
| 35 | const s4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18 | |
| 36 | ||
| 37 | var ix = @bitCast(u32, x); | |
| 38 | const sign = ix >> 31 != 0; | |
| 39 | ix &= 0x7fffffff; | |
| 40 | ||
| 41 | if (ix <= 0x3f490fda) { // |x| ~<= pi/4 | |
| 42 | if (ix < 0x39800000) { // |x| < 2**-12 | |
| 43 | // raise inexact if x!=0 and underflow if subnormal | |
| 44 | math.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120); | |
| 45 | return x; | |
| 46 | } | |
| 47 | return kernel.__sindf(x); | |
| 48 | } | |
| 49 | if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4 | |
| 50 | if (ix <= 0x4016cbe3) { // |x| ~<= 3pi/4 | |
| 51 | if (sign) { | |
| 52 | return -kernel.__cosdf(x + s1pio2); | |
| 53 | } else { | |
| 54 | return kernel.__cosdf(x - s1pio2); | |
| 55 | } | |
| 56 | } | |
| 57 | return kernel.__sindf(if (sign) -(x + s2pio2) else -(x - s2pio2)); | |
| 58 | } | |
| 59 | if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4 | |
| 60 | if (ix <= 0x40afeddf) { // |x| ~<= 7*pi/4 | |
| 61 | if (sign) { | |
| 62 | return kernel.__cosdf(x + s3pio2); | |
| 63 | } else { | |
| 64 | return -kernel.__cosdf(x - s3pio2); | |
| 65 | } | |
| 66 | } | |
| 67 | return kernel.__sindf(if (sign) x + s4pio2 else x - s4pio2); | |
| 68 | } | |
| 69 | ||
| 70 | // sin(Inf or NaN) is NaN | |
| 71 | if (ix >= 0x7f800000) { | |
| 72 | return x - x; | |
| 73 | } | |
| 74 | ||
| 75 | var y: f64 = undefined; | |
| 76 | const n = __rem_pio2f(x, &y); | |
| 77 | return switch (n & 3) { | |
| 78 | 0 => kernel.__sindf(y), | |
| 79 | 1 => kernel.__cosdf(y), | |
| 80 | 2 => kernel.__sindf(-y), | |
| 81 | else => -kernel.__cosdf(y), | |
| 82 | }; | |
| 83 | } | |
| 84 | ||
| 85 | fn sin64(x: f64) f64 { | |
| 86 | var ix = @bitCast(u64, x) >> 32; | |
| 87 | ix &= 0x7fffffff; | |
| 88 | ||
| 89 | // |x| ~< pi/4 | |
| 90 | if (ix <= 0x3fe921fb) { | |
| 91 | if (ix < 0x3e500000) { // |x| < 2**-26 | |
| 92 | // raise inexact if x != 0 and underflow if subnormal | |
| 93 | math.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120); | |
| 94 | return x; | |
| 95 | } | |
| 96 | return kernel.__sin(x, 0.0, 0); | |
| 97 | } | |
| 98 | ||
| 99 | // sin(Inf or NaN) is NaN | |
| 100 | if (ix >= 0x7ff00000) { | |
| 101 | return x - x; | |
| 102 | } | |
| 103 | ||
| 104 | var y: [2]f64 = undefined; | |
| 105 | const n = __rem_pio2(x, &y); | |
| 106 | return switch (n & 3) { | |
| 107 | 0 => kernel.__sin(y[0], y[1], 1), | |
| 108 | 1 => kernel.__cos(y[0], y[1]), | |
| 109 | 2 => -kernel.__sin(y[0], y[1], 1), | |
| 110 | else => -kernel.__cos(y[0], y[1]), | |
| 111 | }; | |
| 112 | } | |
| 113 | ||
| 114 | test "math.sin" { | |
| 115 | try expect(sin(@as(f32, 0.0)) == sin32(0.0)); | |
| 116 | try expect(sin(@as(f64, 0.0)) == sin64(0.0)); | |
| 117 | try expect(comptime (math.sin(@as(f64, 2))) == math.sin(@as(f64, 2))); | |
| 118 | } | |
| 119 | ||
| 120 | test "math.sin32" { | |
| 121 | const epsilon = 0.00001; | |
| 122 | ||
| 123 | try expect(math.approxEqAbs(f32, sin32(0.0), 0.0, epsilon)); | |
| 124 | try expect(math.approxEqAbs(f32, sin32(0.2), 0.198669, epsilon)); | |
| 125 | try expect(math.approxEqAbs(f32, sin32(0.8923), 0.778517, epsilon)); | |
| 126 | try expect(math.approxEqAbs(f32, sin32(1.5), 0.997495, epsilon)); | |
| 127 | try expect(math.approxEqAbs(f32, sin32(-1.5), -0.997495, epsilon)); | |
| 128 | try expect(math.approxEqAbs(f32, sin32(37.45), -0.246544, epsilon)); | |
| 129 | try expect(math.approxEqAbs(f32, sin32(89.123), 0.916166, epsilon)); | |
| 130 | } | |
| 131 | ||
| 132 | test "math.sin64" { | |
| 133 | const epsilon = 0.000001; | |
| 134 | ||
| 135 | try expect(math.approxEqAbs(f64, sin64(0.0), 0.0, epsilon)); | |
| 136 | try expect(math.approxEqAbs(f64, sin64(0.2), 0.198669, epsilon)); | |
| 137 | try expect(math.approxEqAbs(f64, sin64(0.8923), 0.778517, epsilon)); | |
| 138 | try expect(math.approxEqAbs(f64, sin64(1.5), 0.997495, epsilon)); | |
| 139 | try expect(math.approxEqAbs(f64, sin64(-1.5), -0.997495, epsilon)); | |
| 140 | try expect(math.approxEqAbs(f64, sin64(37.45), -0.246543, epsilon)); | |
| 141 | try expect(math.approxEqAbs(f64, sin64(89.123), 0.916166, epsilon)); | |
| 142 | } | |
| 143 | ||
| 144 | test "math.sin32.special" { | |
| 145 | try expect(sin32(0.0) == 0.0); | |
| 146 | try expect(sin32(-0.0) == -0.0); | |
| 147 | try expect(math.isNan(sin32(math.inf(f32)))); | |
| 148 | try expect(math.isNan(sin32(-math.inf(f32)))); | |
| 149 | try expect(math.isNan(sin32(math.nan(f32)))); | |
| 150 | } | |
| 151 | ||
| 152 | test "math.sin64.special" { | |
| 153 | try expect(sin64(0.0) == 0.0); | |
| 154 | try expect(sin64(-0.0) == -0.0); | |
| 155 | try expect(math.isNan(sin64(math.inf(f64)))); | |
| 156 | try expect(math.isNan(sin64(-math.inf(f64)))); | |
| 157 | try expect(math.isNan(sin64(math.nan(f64)))); | |
| 158 | } | |
| 159 | ||
| 160 | test "math.sin32 #9901" { | |
| 161 | const float = @bitCast(f32, @as(u32, 0b11100011111111110000000000000000)); | |
| 162 | _ = std.math.sin(float); | |
| 163 | } | |
| 164 | ||
| 165 | test "math.sin64 #9901" { | |
| 166 | const float = @bitCast(f64, @as(u64, 0b1111111101000001000000001111110111111111100000000000000000000001)); | |
| 167 | _ = std.math.sin(float); | |
| 168 | } |
lib/std/math/tan.zig deleted-140| ... | ... | @@ -1,140 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/tanf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/tan.c | |
| 6 | // https://golang.org/src/math/tan.go | |
| 7 | ||
| 8 | const std = @import("../std.zig"); | |
| 9 | const math = std.math; | |
| 10 | const expect = std.testing.expect; | |
| 11 | ||
| 12 | const kernel = @import("__trig.zig"); | |
| 13 | const __rem_pio2 = @import("__rem_pio2.zig").__rem_pio2; | |
| 14 | const __rem_pio2f = @import("__rem_pio2f.zig").__rem_pio2f; | |
| 15 | ||
| 16 | /// Returns the tangent of the radian value x. | |
| 17 | /// | |
| 18 | /// Special Cases: | |
| 19 | /// - tan(+-0) = +-0 | |
| 20 | /// - tan(+-inf) = nan | |
| 21 | /// - tan(nan) = nan | |
| 22 | pub fn tan(x: anytype) @TypeOf(x) { | |
| 23 | const T = @TypeOf(x); | |
| 24 | return switch (T) { | |
| 25 | f32 => tan32(x), | |
| 26 | f64 => tan64(x), | |
| 27 | else => @compileError("tan not implemented for " ++ @typeName(T)), | |
| 28 | }; | |
| 29 | } | |
| 30 | ||
| 31 | fn tan32(x: f32) f32 { | |
| 32 | // Small multiples of pi/2 rounded to double precision. | |
| 33 | const t1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 | |
| 34 | const t2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 | |
| 35 | const t3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2 | |
| 36 | const t4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18 | |
| 37 | ||
| 38 | var ix = @bitCast(u32, x); | |
| 39 | const sign = ix >> 31 != 0; | |
| 40 | ix &= 0x7fffffff; | |
| 41 | ||
| 42 | if (ix <= 0x3f490fda) { // |x| ~<= pi/4 | |
| 43 | if (ix < 0x39800000) { // |x| < 2**-12 | |
| 44 | // raise inexact if x!=0 and underflow if subnormal | |
| 45 | math.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120); | |
| 46 | return x; | |
| 47 | } | |
| 48 | return kernel.__tandf(x, false); | |
| 49 | } | |
| 50 | if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4 | |
| 51 | if (ix <= 0x4016cbe3) { // |x| ~<= 3pi/4 | |
| 52 | return kernel.__tandf((if (sign) x + t1pio2 else x - t1pio2), true); | |
| 53 | } else { | |
| 54 | return kernel.__tandf((if (sign) x + t2pio2 else x - t2pio2), false); | |
| 55 | } | |
| 56 | } | |
| 57 | if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4 | |
| 58 | if (ix <= 0x40afeddf) { // |x| ~<= 7*pi/4 | |
| 59 | return kernel.__tandf((if (sign) x + t3pio2 else x - t3pio2), true); | |
| 60 | } else { | |
| 61 | return kernel.__tandf((if (sign) x + t4pio2 else x - t4pio2), false); | |
| 62 | } | |
| 63 | } | |
| 64 | ||
| 65 | // tan(Inf or NaN) is NaN | |
| 66 | if (ix >= 0x7f800000) { | |
| 67 | return x - x; | |
| 68 | } | |
| 69 | ||
| 70 | var y: f64 = undefined; | |
| 71 | const n = __rem_pio2f(x, &y); | |
| 72 | return kernel.__tandf(y, n & 1 != 0); | |
| 73 | } | |
| 74 | ||
| 75 | fn tan64(x: f64) f64 { | |
| 76 | var ix = @bitCast(u64, x) >> 32; | |
| 77 | ix &= 0x7fffffff; | |
| 78 | ||
| 79 | // |x| ~< pi/4 | |
| 80 | if (ix <= 0x3fe921fb) { | |
| 81 | if (ix < 0x3e400000) { // |x| < 2**-27 | |
| 82 | // raise inexact if x!=0 and underflow if subnormal | |
| 83 | math.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120); | |
| 84 | return x; | |
| 85 | } | |
| 86 | return kernel.__tan(x, 0.0, false); | |
| 87 | } | |
| 88 | ||
| 89 | // tan(Inf or NaN) is NaN | |
| 90 | if (ix >= 0x7ff00000) { | |
| 91 | return x - x; | |
| 92 | } | |
| 93 | ||
| 94 | var y: [2]f64 = undefined; | |
| 95 | const n = __rem_pio2(x, &y); | |
| 96 | return kernel.__tan(y[0], y[1], n & 1 != 0); | |
| 97 | } | |
| 98 | ||
| 99 | test "math.tan" { | |
| 100 | try expect(tan(@as(f32, 0.0)) == tan32(0.0)); | |
| 101 | try expect(tan(@as(f64, 0.0)) == tan64(0.0)); | |
| 102 | } | |
| 103 | ||
| 104 | test "math.tan32" { | |
| 105 | const epsilon = 0.00001; | |
| 106 | ||
| 107 | try expect(math.approxEqAbs(f32, tan32(0.0), 0.0, epsilon)); | |
| 108 | try expect(math.approxEqAbs(f32, tan32(0.2), 0.202710, epsilon)); | |
| 109 | try expect(math.approxEqAbs(f32, tan32(0.8923), 1.240422, epsilon)); | |
| 110 | try expect(math.approxEqAbs(f32, tan32(1.5), 14.101420, epsilon)); | |
| 111 | try expect(math.approxEqAbs(f32, tan32(37.45), -0.254397, epsilon)); | |
| 112 | try expect(math.approxEqAbs(f32, tan32(89.123), 2.285852, epsilon)); | |
| 113 | } | |
| 114 | ||
| 115 | test "math.tan64" { | |
| 116 | const epsilon = 0.000001; | |
| 117 | ||
| 118 | try expect(math.approxEqAbs(f64, tan64(0.0), 0.0, epsilon)); | |
| 119 | try expect(math.approxEqAbs(f64, tan64(0.2), 0.202710, epsilon)); | |
| 120 | try expect(math.approxEqAbs(f64, tan64(0.8923), 1.240422, epsilon)); | |
| 121 | try expect(math.approxEqAbs(f64, tan64(1.5), 14.101420, epsilon)); | |
| 122 | try expect(math.approxEqAbs(f64, tan64(37.45), -0.254397, epsilon)); | |
| 123 | try expect(math.approxEqAbs(f64, tan64(89.123), 2.2858376, epsilon)); | |
| 124 | } | |
| 125 | ||
| 126 | test "math.tan32.special" { | |
| 127 | try expect(tan32(0.0) == 0.0); | |
| 128 | try expect(tan32(-0.0) == -0.0); | |
| 129 | try expect(math.isNan(tan32(math.inf(f32)))); | |
| 130 | try expect(math.isNan(tan32(-math.inf(f32)))); | |
| 131 | try expect(math.isNan(tan32(math.nan(f32)))); | |
| 132 | } | |
| 133 | ||
| 134 | test "math.tan64.special" { | |
| 135 | try expect(tan64(0.0) == 0.0); | |
| 136 | try expect(tan64(-0.0) == -0.0); | |
| 137 | try expect(math.isNan(tan64(math.inf(f64)))); | |
| 138 | try expect(math.isNan(tan64(-math.inf(f64)))); | |
| 139 | try expect(math.isNan(tan64(math.nan(f64)))); | |
| 140 | } |
lib/std/math/trunc.zig deleted-141| ... | ... | @@ -1,141 +0,0 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/truncf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c | |
| 6 | ||
| 7 | const std = @import("../std.zig"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | const maxInt = std.math.maxInt; | |
| 11 | ||
| 12 | /// Returns the integer value of x. | |
| 13 | /// | |
| 14 | /// Special Cases: | |
| 15 | /// - trunc(+-0) = +-0 | |
| 16 | /// - trunc(+-inf) = +-inf | |
| 17 | /// - trunc(nan) = nan | |
| 18 | pub fn trunc(x: anytype) @TypeOf(x) { | |
| 19 | const T = @TypeOf(x); | |
| 20 | return switch (T) { | |
| 21 | f32 => trunc32(x), | |
| 22 | f64 => trunc64(x), | |
| 23 | f128 => trunc128(x), | |
| 24 | ||
| 25 | // TODO this is not correct for some targets | |
| 26 | c_longdouble => @floatCast(c_longdouble, trunc128(x)), | |
| 27 | ||
| 28 | else => @compileError("trunc not implemented for " ++ @typeName(T)), | |
| 29 | }; | |
| 30 | } | |
| 31 | ||
| 32 | fn trunc32(x: f32) f32 { | |
| 33 | const u = @bitCast(u32, x); | |
| 34 | var e = @intCast(i32, ((u >> 23) & 0xFF)) - 0x7F + 9; | |
| 35 | var m: u32 = undefined; | |
| 36 | ||
| 37 | if (e >= 23 + 9) { | |
| 38 | return x; | |
| 39 | } | |
| 40 | if (e < 9) { | |
| 41 | e = 1; | |
| 42 | } | |
| 43 | ||
| 44 | m = @as(u32, maxInt(u32)) >> @intCast(u5, e); | |
| 45 | if (u & m == 0) { | |
| 46 | return x; | |
| 47 | } else { | |
| 48 | math.doNotOptimizeAway(x + 0x1p120); | |
| 49 | return @bitCast(f32, u & ~m); | |
| 50 | } | |
| 51 | } | |
| 52 | ||
| 53 | fn trunc64(x: f64) f64 { | |
| 54 | const u = @bitCast(u64, x); | |
| 55 | var e = @intCast(i32, ((u >> 52) & 0x7FF)) - 0x3FF + 12; | |
| 56 | var m: u64 = undefined; | |
| 57 | ||
| 58 | if (e >= 52 + 12) { | |
| 59 | return x; | |
| 60 | } | |
| 61 | if (e < 12) { | |
| 62 | e = 1; | |
| 63 | } | |
| 64 | ||
| 65 | m = @as(u64, maxInt(u64)) >> @intCast(u6, e); | |
| 66 | if (u & m == 0) { | |
| 67 | return x; | |
| 68 | } else { | |
| 69 | math.doNotOptimizeAway(x + 0x1p120); | |
| 70 | return @bitCast(f64, u & ~m); | |
| 71 | } | |
| 72 | } | |
| 73 | ||
| 74 | fn trunc128(x: f128) f128 { | |
| 75 | const u = @bitCast(u128, x); | |
| 76 | var e = @intCast(i32, ((u >> 112) & 0x7FFF)) - 0x3FFF + 16; | |
| 77 | var m: u128 = undefined; | |
| 78 | ||
| 79 | if (e >= 112 + 16) { | |
| 80 | return x; | |
| 81 | } | |
| 82 | if (e < 16) { | |
| 83 | e = 1; | |
| 84 | } | |
| 85 | ||
| 86 | m = @as(u128, maxInt(u128)) >> @intCast(u7, e); | |
| 87 | if (u & m == 0) { | |
| 88 | return x; | |
| 89 | } else { | |
| 90 | math.doNotOptimizeAway(x + 0x1p120); | |
| 91 | return @bitCast(f128, u & ~m); | |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | test "math.trunc" { | |
| 96 | try expect(trunc(@as(f32, 1.3)) == trunc32(1.3)); | |
| 97 | try expect(trunc(@as(f64, 1.3)) == trunc64(1.3)); | |
| 98 | try expect(trunc(@as(f128, 1.3)) == trunc128(1.3)); | |
| 99 | } | |
| 100 | ||
| 101 | test "math.trunc32" { | |
| 102 | try expect(trunc32(1.3) == 1.0); | |
| 103 | try expect(trunc32(-1.3) == -1.0); | |
| 104 | try expect(trunc32(0.2) == 0.0); | |
| 105 | } | |
| 106 | ||
| 107 | test "math.trunc64" { | |
| 108 | try expect(trunc64(1.3) == 1.0); | |
| 109 | try expect(trunc64(-1.3) == -1.0); | |
| 110 | try expect(trunc64(0.2) == 0.0); | |
| 111 | } | |
| 112 | ||
| 113 | test "math.trunc128" { | |
| 114 | try expect(trunc128(1.3) == 1.0); | |
| 115 | try expect(trunc128(-1.3) == -1.0); | |
| 116 | try expect(trunc128(0.2) == 0.0); | |
| 117 | } | |
| 118 | ||
| 119 | test "math.trunc32.special" { | |
| 120 | try expect(trunc32(0.0) == 0.0); // 0x3F800000 | |
| 121 | try expect(trunc32(-0.0) == -0.0); | |
| 122 | try expect(math.isPositiveInf(trunc32(math.inf(f32)))); | |
| 123 | try expect(math.isNegativeInf(trunc32(-math.inf(f32)))); | |
| 124 | try expect(math.isNan(trunc32(math.nan(f32)))); | |
| 125 | } | |
| 126 | ||
| 127 | test "math.trunc64.special" { | |
| 128 | try expect(trunc64(0.0) == 0.0); | |
| 129 | try expect(trunc64(-0.0) == -0.0); | |
| 130 | try expect(math.isPositiveInf(trunc64(math.inf(f64)))); | |
| 131 | try expect(math.isNegativeInf(trunc64(-math.inf(f64)))); | |
| 132 | try expect(math.isNan(trunc64(math.nan(f64)))); | |
| 133 | } | |
| 134 | ||
| 135 | test "math.trunc128.special" { | |
| 136 | try expect(trunc128(0.0) == 0.0); | |
| 137 | try expect(trunc128(-0.0) == -0.0); | |
| 138 | try expect(math.isPositiveInf(trunc128(math.inf(f128)))); | |
| 139 | try expect(math.isNegativeInf(trunc128(-math.inf(f128)))); | |
| 140 | try expect(math.isNan(trunc128(math.nan(f128)))); | |
| 141 | } |
lib/std/rand/ziggurat.zig+8-8| ... | ... | @@ -33,7 +33,7 @@ pub fn next_f64(random: Random, comptime tables: ZigTable) f64 { |
| 33 | 33 | }; |
| 34 | 34 | |
| 35 | 35 | const x = u * tables.x[i]; |
| 36 | const test_x = if (tables.is_symmetric) math.fabs(x) else x; | |
| 36 | const test_x = if (tables.is_symmetric) @fabs(x) else x; | |
| 37 | 37 | |
| 38 | 38 | // equivalent to |u| < tables.x[i+1] / tables.x[i] (or u < tables.x[i+1] / tables.x[i]) |
| 39 | 39 | if (test_x < tables.x[i + 1]) { |
| ... | ... | @@ -106,18 +106,18 @@ const norm_r = 3.6541528853610088; |
| 106 | 106 | const norm_v = 0.00492867323399; |
| 107 | 107 | |
| 108 | 108 | fn norm_f(x: f64) f64 { |
| 109 | return math.exp(-x * x / 2.0); | |
| 109 | return @exp(-x * x / 2.0); | |
| 110 | 110 | } |
| 111 | 111 | fn norm_f_inv(y: f64) f64 { |
| 112 | return math.sqrt(-2.0 * math.ln(y)); | |
| 112 | return @sqrt(-2.0 * @log(y)); | |
| 113 | 113 | } |
| 114 | 114 | fn norm_zero_case(random: Random, u: f64) f64 { |
| 115 | 115 | var x: f64 = 1; |
| 116 | 116 | var y: f64 = 0; |
| 117 | 117 | |
| 118 | 118 | while (-2.0 * y < x * x) { |
| 119 | x = math.ln(random.float(f64)) / norm_r; | |
| 120 | y = math.ln(random.float(f64)); | |
| 119 | x = @log(random.float(f64)) / norm_r; | |
| 120 | y = @log(random.float(f64)); | |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | 123 | if (u < 0) { |
| ... | ... | @@ -151,13 +151,13 @@ const exp_r = 7.69711747013104972; |
| 151 | 151 | const exp_v = 0.0039496598225815571993; |
| 152 | 152 | |
| 153 | 153 | fn exp_f(x: f64) f64 { |
| 154 | return math.exp(-x); | |
| 154 | return @exp(-x); | |
| 155 | 155 | } |
| 156 | 156 | fn exp_f_inv(y: f64) f64 { |
| 157 | return -math.ln(y); | |
| 157 | return -@log(y); | |
| 158 | 158 | } |
| 159 | 159 | fn exp_zero_case(random: Random, _: f64) f64 { |
| 160 | return exp_r - math.ln(random.float(f64)); | |
| 160 | return exp_r - @log(random.float(f64)); | |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | test "exp dist sanity" { |
lib/std/special/c.zig-591| ... | ... | @@ -12,7 +12,6 @@ const maxInt = std.math.maxInt; |
| 12 | 12 | const native_os = builtin.os.tag; |
| 13 | 13 | const native_arch = builtin.cpu.arch; |
| 14 | 14 | const native_abi = builtin.abi; |
| 15 | const long_double_is_f128 = builtin.target.longDoubleIs(f128); | |
| 16 | 15 | |
| 17 | 16 | const is_wasm = switch (native_arch) { |
| 18 | 17 | .wasm32, .wasm64 => true, |
| ... | ... | @@ -55,53 +54,6 @@ comptime { |
| 55 | 54 | } else if (is_msvc) { |
| 56 | 55 | @export(_fltused, .{ .name = "_fltused", .linkage = .Strong }); |
| 57 | 56 | } |
| 58 | ||
| 59 | @export(trunc, .{ .name = "trunc", .linkage = .Strong }); | |
| 60 | @export(truncf, .{ .name = "truncf", .linkage = .Strong }); | |
| 61 | @export(truncl, .{ .name = "truncl", .linkage = .Strong }); | |
| 62 | ||
| 63 | @export(log, .{ .name = "log", .linkage = .Strong }); | |
| 64 | @export(logf, .{ .name = "logf", .linkage = .Strong }); | |
| 65 | ||
| 66 | @export(sin, .{ .name = "sin", .linkage = .Strong }); | |
| 67 | @export(sinf, .{ .name = "sinf", .linkage = .Strong }); | |
| 68 | ||
| 69 | @export(cos, .{ .name = "cos", .linkage = .Strong }); | |
| 70 | @export(cosf, .{ .name = "cosf", .linkage = .Strong }); | |
| 71 | ||
| 72 | @export(exp, .{ .name = "exp", .linkage = .Strong }); | |
| 73 | @export(expf, .{ .name = "expf", .linkage = .Strong }); | |
| 74 | ||
| 75 | @export(exp2, .{ .name = "exp2", .linkage = .Strong }); | |
| 76 | @export(exp2f, .{ .name = "exp2f", .linkage = .Strong }); | |
| 77 | ||
| 78 | @export(log2, .{ .name = "log2", .linkage = .Strong }); | |
| 79 | @export(log2f, .{ .name = "log2f", .linkage = .Strong }); | |
| 80 | ||
| 81 | @export(log10, .{ .name = "log10", .linkage = .Strong }); | |
| 82 | @export(log10f, .{ .name = "log10f", .linkage = .Strong }); | |
| 83 | ||
| 84 | @export(fmod, .{ .name = "fmod", .linkage = .Strong }); | |
| 85 | @export(fmodf, .{ .name = "fmodf", .linkage = .Strong }); | |
| 86 | ||
| 87 | @export(sincos, .{ .name = "sincos", .linkage = .Strong }); | |
| 88 | @export(sincosf, .{ .name = "sincosf", .linkage = .Strong }); | |
| 89 | ||
| 90 | @export(fabs, .{ .name = "fabs", .linkage = .Strong }); | |
| 91 | @export(fabsf, .{ .name = "fabsf", .linkage = .Strong }); | |
| 92 | ||
| 93 | @export(round, .{ .name = "round", .linkage = .Strong }); | |
| 94 | @export(roundf, .{ .name = "roundf", .linkage = .Strong }); | |
| 95 | @export(roundl, .{ .name = "roundl", .linkage = .Strong }); | |
| 96 | ||
| 97 | @export(fmin, .{ .name = "fmin", .linkage = .Strong }); | |
| 98 | @export(fminf, .{ .name = "fminf", .linkage = .Strong }); | |
| 99 | ||
| 100 | @export(fmax, .{ .name = "fmax", .linkage = .Strong }); | |
| 101 | @export(fmaxf, .{ .name = "fmaxf", .linkage = .Strong }); | |
| 102 | ||
| 103 | @export(sqrt, .{ .name = "sqrt", .linkage = .Strong }); | |
| 104 | @export(sqrtf, .{ .name = "sqrtf", .linkage = .Strong }); | |
| 105 | 57 | } |
| 106 | 58 | |
| 107 | 59 | // Avoid dragging in the runtime safety mechanisms into this .o file, |
| ... | ... | @@ -352,549 +304,6 @@ test "strncmp" { |
| 352 | 304 | try std.testing.expect(strncmp("\xff", "\x02", 1) == 253); |
| 353 | 305 | } |
| 354 | 306 | |
| 355 | fn trunc(a: f64) callconv(.C) f64 { | |
| 356 | return math.trunc(a); | |
| 357 | } | |
| 358 | ||
| 359 | fn truncf(a: f32) callconv(.C) f32 { | |
| 360 | return math.trunc(a); | |
| 361 | } | |
| 362 | ||
| 363 | fn truncl(a: c_longdouble) callconv(.C) c_longdouble { | |
| 364 | if (!long_double_is_f128) { | |
| 365 | @panic("TODO implement this"); | |
| 366 | } | |
| 367 | return math.trunc(a); | |
| 368 | } | |
| 369 | ||
| 370 | fn log(a: f64) callconv(.C) f64 { | |
| 371 | return math.ln(a); | |
| 372 | } | |
| 373 | ||
| 374 | fn logf(a: f32) callconv(.C) f32 { | |
| 375 | return math.ln(a); | |
| 376 | } | |
| 377 | ||
| 378 | fn sin(a: f64) callconv(.C) f64 { | |
| 379 | return math.sin(a); | |
| 380 | } | |
| 381 | ||
| 382 | fn sinf(a: f32) callconv(.C) f32 { | |
| 383 | return math.sin(a); | |
| 384 | } | |
| 385 | ||
| 386 | fn cos(a: f64) callconv(.C) f64 { | |
| 387 | return math.cos(a); | |
| 388 | } | |
| 389 | ||
| 390 | fn cosf(a: f32) callconv(.C) f32 { | |
| 391 | return math.cos(a); | |
| 392 | } | |
| 393 | ||
| 394 | fn exp(a: f64) callconv(.C) f64 { | |
| 395 | return math.exp(a); | |
| 396 | } | |
| 397 | ||
| 398 | fn expf(a: f32) callconv(.C) f32 { | |
| 399 | return math.exp(a); | |
| 400 | } | |
| 401 | ||
| 402 | fn exp2(a: f64) callconv(.C) f64 { | |
| 403 | return math.exp2(a); | |
| 404 | } | |
| 405 | ||
| 406 | fn exp2f(a: f32) callconv(.C) f32 { | |
| 407 | return math.exp2(a); | |
| 408 | } | |
| 409 | ||
| 410 | fn log2(a: f64) callconv(.C) f64 { | |
| 411 | return math.log2(a); | |
| 412 | } | |
| 413 | ||
| 414 | fn log2f(a: f32) callconv(.C) f32 { | |
| 415 | return math.log2(a); | |
| 416 | } | |
| 417 | ||
| 418 | fn log10(a: f64) callconv(.C) f64 { | |
| 419 | return math.log10(a); | |
| 420 | } | |
| 421 | ||
| 422 | fn log10f(a: f32) callconv(.C) f32 { | |
| 423 | return math.log10(a); | |
| 424 | } | |
| 425 | ||
| 426 | fn fmodf(x: f32, y: f32) callconv(.C) f32 { | |
| 427 | return generic_fmod(f32, x, y); | |
| 428 | } | |
| 429 | fn fmod(x: f64, y: f64) callconv(.C) f64 { | |
| 430 | return generic_fmod(f64, x, y); | |
| 431 | } | |
| 432 | ||
| 433 | fn generic_fmod(comptime T: type, x: T, y: T) T { | |
| 434 | @setRuntimeSafety(false); | |
| 435 | ||
| 436 | const bits = @typeInfo(T).Float.bits; | |
| 437 | const uint = std.meta.Int(.unsigned, bits); | |
| 438 | const log2uint = math.Log2Int(uint); | |
| 439 | const digits = if (T == f32) 23 else 52; | |
| 440 | const exp_bits = if (T == f32) 9 else 12; | |
| 441 | const bits_minus_1 = bits - 1; | |
| 442 | const mask = if (T == f32) 0xff else 0x7ff; | |
| 443 | var ux = @bitCast(uint, x); | |
| 444 | var uy = @bitCast(uint, y); | |
| 445 | var ex = @intCast(i32, (ux >> digits) & mask); | |
| 446 | var ey = @intCast(i32, (uy >> digits) & mask); | |
| 447 | const sx = if (T == f32) @intCast(u32, ux & 0x80000000) else @intCast(i32, ux >> bits_minus_1); | |
| 448 | var i: uint = undefined; | |
| 449 | ||
| 450 | if (uy << 1 == 0 or isNan(@bitCast(T, uy)) or ex == mask) | |
| 451 | return (x * y) / (x * y); | |
| 452 | ||
| 453 | if (ux << 1 <= uy << 1) { | |
| 454 | if (ux << 1 == uy << 1) | |
| 455 | return 0 * x; | |
| 456 | return x; | |
| 457 | } | |
| 458 | ||
| 459 | // normalize x and y | |
| 460 | if (ex == 0) { | |
| 461 | i = ux << exp_bits; | |
| 462 | while (i >> bits_minus_1 == 0) : ({ | |
| 463 | ex -= 1; | |
| 464 | i <<= 1; | |
| 465 | }) {} | |
| 466 | ux <<= @intCast(log2uint, @bitCast(u32, -ex + 1)); | |
| 467 | } else { | |
| 468 | ux &= maxInt(uint) >> exp_bits; | |
| 469 | ux |= 1 << digits; | |
| 470 | } | |
| 471 | if (ey == 0) { | |
| 472 | i = uy << exp_bits; | |
| 473 | while (i >> bits_minus_1 == 0) : ({ | |
| 474 | ey -= 1; | |
| 475 | i <<= 1; | |
| 476 | }) {} | |
| 477 | uy <<= @intCast(log2uint, @bitCast(u32, -ey + 1)); | |
| 478 | } else { | |
| 479 | uy &= maxInt(uint) >> exp_bits; | |
| 480 | uy |= 1 << digits; | |
| 481 | } | |
| 482 | ||
| 483 | // x mod y | |
| 484 | while (ex > ey) : (ex -= 1) { | |
| 485 | i = ux -% uy; | |
| 486 | if (i >> bits_minus_1 == 0) { | |
| 487 | if (i == 0) | |
| 488 | return 0 * x; | |
| 489 | ux = i; | |
| 490 | } | |
| 491 | ux <<= 1; | |
| 492 | } | |
| 493 | i = ux -% uy; | |
| 494 | if (i >> bits_minus_1 == 0) { | |
| 495 | if (i == 0) | |
| 496 | return 0 * x; | |
| 497 | ux = i; | |
| 498 | } | |
| 499 | while (ux >> digits == 0) : ({ | |
| 500 | ux <<= 1; | |
| 501 | ex -= 1; | |
| 502 | }) {} | |
| 503 | ||
| 504 | // scale result up | |
| 505 | if (ex > 0) { | |
| 506 | ux -%= 1 << digits; | |
| 507 | ux |= @as(uint, @bitCast(u32, ex)) << digits; | |
| 508 | } else { | |
| 509 | ux >>= @intCast(log2uint, @bitCast(u32, -ex + 1)); | |
| 510 | } | |
| 511 | if (T == f32) { | |
| 512 | ux |= sx; | |
| 513 | } else { | |
| 514 | ux |= @intCast(uint, sx) << bits_minus_1; | |
| 515 | } | |
| 516 | return @bitCast(T, ux); | |
| 517 | } | |
| 518 | ||
| 519 | test "fmod, fmodf" { | |
| 520 | inline for ([_]type{ f32, f64 }) |T| { | |
| 521 | const nan_val = math.nan(T); | |
| 522 | const inf_val = math.inf(T); | |
| 523 | ||
| 524 | try std.testing.expect(isNan(generic_fmod(T, nan_val, 1.0))); | |
| 525 | try std.testing.expect(isNan(generic_fmod(T, 1.0, nan_val))); | |
| 526 | try std.testing.expect(isNan(generic_fmod(T, inf_val, 1.0))); | |
| 527 | try std.testing.expect(isNan(generic_fmod(T, 0.0, 0.0))); | |
| 528 | try std.testing.expect(isNan(generic_fmod(T, 1.0, 0.0))); | |
| 529 | ||
| 530 | try std.testing.expectEqual(@as(T, 0.0), generic_fmod(T, 0.0, 2.0)); | |
| 531 | try std.testing.expectEqual(@as(T, -0.0), generic_fmod(T, -0.0, 2.0)); | |
| 532 | ||
| 533 | try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, 10.0)); | |
| 534 | try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, -10.0)); | |
| 535 | try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, 10.0)); | |
| 536 | try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, -10.0)); | |
| 537 | } | |
| 538 | } | |
| 539 | ||
| 540 | fn sincos(a: f64, r_sin: *f64, r_cos: *f64) callconv(.C) void { | |
| 541 | r_sin.* = math.sin(a); | |
| 542 | r_cos.* = math.cos(a); | |
| 543 | } | |
| 544 | ||
| 545 | fn sincosf(a: f32, r_sin: *f32, r_cos: *f32) callconv(.C) void { | |
| 546 | r_sin.* = math.sin(a); | |
| 547 | r_cos.* = math.cos(a); | |
| 548 | } | |
| 549 | ||
| 550 | fn fabs(a: f64) callconv(.C) f64 { | |
| 551 | return math.fabs(a); | |
| 552 | } | |
| 553 | ||
| 554 | fn fabsf(a: f32) callconv(.C) f32 { | |
| 555 | return math.fabs(a); | |
| 556 | } | |
| 557 | ||
| 558 | fn roundf(a: f32) callconv(.C) f32 { | |
| 559 | return math.round(a); | |
| 560 | } | |
| 561 | ||
| 562 | fn round(a: f64) callconv(.C) f64 { | |
| 563 | return math.round(a); | |
| 564 | } | |
| 565 | ||
| 566 | fn roundl(a: c_longdouble) callconv(.C) c_longdouble { | |
| 567 | if (!long_double_is_f128) { | |
| 568 | @panic("TODO implement this"); | |
| 569 | } | |
| 570 | return math.round(a); | |
| 571 | } | |
| 572 | ||
| 573 | fn fminf(x: f32, y: f32) callconv(.C) f32 { | |
| 574 | return generic_fmin(f32, x, y); | |
| 575 | } | |
| 576 | ||
| 577 | fn fmin(x: f64, y: f64) callconv(.C) f64 { | |
| 578 | return generic_fmin(f64, x, y); | |
| 579 | } | |
| 580 | ||
| 581 | fn generic_fmin(comptime T: type, x: T, y: T) T { | |
| 582 | if (isNan(x)) | |
| 583 | return y; | |
| 584 | if (isNan(y)) | |
| 585 | return x; | |
| 586 | return if (x < y) x else y; | |
| 587 | } | |
| 588 | ||
| 589 | test "fmin, fminf" { | |
| 590 | inline for ([_]type{ f32, f64 }) |T| { | |
| 591 | const nan_val = math.nan(T); | |
| 592 | ||
| 593 | try std.testing.expect(isNan(generic_fmin(T, nan_val, nan_val))); | |
| 594 | try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, nan_val, 1.0)); | |
| 595 | try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, nan_val)); | |
| 596 | ||
| 597 | try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, 10.0)); | |
| 598 | try std.testing.expectEqual(@as(T, -1.0), generic_fmin(T, 1.0, -1.0)); | |
| 599 | } | |
| 600 | } | |
| 601 | ||
| 602 | fn fmaxf(x: f32, y: f32) callconv(.C) f32 { | |
| 603 | return generic_fmax(f32, x, y); | |
| 604 | } | |
| 605 | ||
| 606 | fn fmax(x: f64, y: f64) callconv(.C) f64 { | |
| 607 | return generic_fmax(f64, x, y); | |
| 608 | } | |
| 609 | ||
| 610 | fn generic_fmax(comptime T: type, x: T, y: T) T { | |
| 611 | if (isNan(x)) | |
| 612 | return y; | |
| 613 | if (isNan(y)) | |
| 614 | return x; | |
| 615 | return if (x < y) y else x; | |
| 616 | } | |
| 617 | ||
| 618 | test "fmax, fmaxf" { | |
| 619 | inline for ([_]type{ f32, f64 }) |T| { | |
| 620 | const nan_val = math.nan(T); | |
| 621 | ||
| 622 | try std.testing.expect(isNan(generic_fmax(T, nan_val, nan_val))); | |
| 623 | try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, nan_val, 1.0)); | |
| 624 | try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, nan_val)); | |
| 625 | ||
| 626 | try std.testing.expectEqual(@as(T, 10.0), generic_fmax(T, 1.0, 10.0)); | |
| 627 | try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, -1.0)); | |
| 628 | } | |
| 629 | } | |
| 630 | ||
| 631 | // NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound | |
| 632 | // behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are | |
| 633 | // potentially some edge cases remaining that are not handled in the same way. | |
| 634 | fn sqrt(x: f64) callconv(.C) f64 { | |
| 635 | const tiny: f64 = 1.0e-300; | |
| 636 | const sign: u32 = 0x80000000; | |
| 637 | const u = @bitCast(u64, x); | |
| 638 | ||
| 639 | var ix0 = @intCast(u32, u >> 32); | |
| 640 | var ix1 = @intCast(u32, u & 0xFFFFFFFF); | |
| 641 | ||
| 642 | // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan | |
| 643 | if (ix0 & 0x7FF00000 == 0x7FF00000) { | |
| 644 | return x * x + x; | |
| 645 | } | |
| 646 | ||
| 647 | // sqrt(+-0) = +-0 | |
| 648 | if (x == 0.0) { | |
| 649 | return x; | |
| 650 | } | |
| 651 | // sqrt(-ve) = snan | |
| 652 | if (ix0 & sign != 0) { | |
| 653 | return math.snan(f64); | |
| 654 | } | |
| 655 | ||
| 656 | // normalize x | |
| 657 | var m = @intCast(i32, ix0 >> 20); | |
| 658 | if (m == 0) { | |
| 659 | // subnormal | |
| 660 | while (ix0 == 0) { | |
| 661 | m -= 21; | |
| 662 | ix0 |= ix1 >> 11; | |
| 663 | ix1 <<= 21; | |
| 664 | } | |
| 665 | ||
| 666 | // subnormal | |
| 667 | var i: u32 = 0; | |
| 668 | while (ix0 & 0x00100000 == 0) : (i += 1) { | |
| 669 | ix0 <<= 1; | |
| 670 | } | |
| 671 | m -= @intCast(i32, i) - 1; | |
| 672 | ix0 |= ix1 >> @intCast(u5, 32 - i); | |
| 673 | ix1 <<= @intCast(u5, i); | |
| 674 | } | |
| 675 | ||
| 676 | // unbias exponent | |
| 677 | m -= 1023; | |
| 678 | ix0 = (ix0 & 0x000FFFFF) | 0x00100000; | |
| 679 | if (m & 1 != 0) { | |
| 680 | ix0 += ix0 + (ix1 >> 31); | |
| 681 | ix1 = ix1 +% ix1; | |
| 682 | } | |
| 683 | m >>= 1; | |
| 684 | ||
| 685 | // sqrt(x) bit by bit | |
| 686 | ix0 += ix0 + (ix1 >> 31); | |
| 687 | ix1 = ix1 +% ix1; | |
| 688 | ||
| 689 | var q: u32 = 0; | |
| 690 | var q1: u32 = 0; | |
| 691 | var s0: u32 = 0; | |
| 692 | var s1: u32 = 0; | |
| 693 | var r: u32 = 0x00200000; | |
| 694 | var t: u32 = undefined; | |
| 695 | var t1: u32 = undefined; | |
| 696 | ||
| 697 | while (r != 0) { | |
| 698 | t = s0 +% r; | |
| 699 | if (t <= ix0) { | |
| 700 | s0 = t + r; | |
| 701 | ix0 -= t; | |
| 702 | q += r; | |
| 703 | } | |
| 704 | ix0 = ix0 +% ix0 +% (ix1 >> 31); | |
| 705 | ix1 = ix1 +% ix1; | |
| 706 | r >>= 1; | |
| 707 | } | |
| 708 | ||
| 709 | r = sign; | |
| 710 | while (r != 0) { | |
| 711 | t1 = s1 +% r; | |
| 712 | t = s0; | |
| 713 | if (t < ix0 or (t == ix0 and t1 <= ix1)) { | |
| 714 | s1 = t1 +% r; | |
| 715 | if (t1 & sign == sign and s1 & sign == 0) { | |
| 716 | s0 += 1; | |
| 717 | } | |
| 718 | ix0 -= t; | |
| 719 | if (ix1 < t1) { | |
| 720 | ix0 -= 1; | |
| 721 | } | |
| 722 | ix1 = ix1 -% t1; | |
| 723 | q1 += r; | |
| 724 | } | |
| 725 | ix0 = ix0 +% ix0 +% (ix1 >> 31); | |
| 726 | ix1 = ix1 +% ix1; | |
| 727 | r >>= 1; | |
| 728 | } | |
| 729 | ||
| 730 | // rounding direction | |
| 731 | if (ix0 | ix1 != 0) { | |
| 732 | var z = 1.0 - tiny; // raise inexact | |
| 733 | if (z >= 1.0) { | |
| 734 | z = 1.0 + tiny; | |
| 735 | if (q1 == 0xFFFFFFFF) { | |
| 736 | q1 = 0; | |
| 737 | q += 1; | |
| 738 | } else if (z > 1.0) { | |
| 739 | if (q1 == 0xFFFFFFFE) { | |
| 740 | q += 1; | |
| 741 | } | |
| 742 | q1 += 2; | |
| 743 | } else { | |
| 744 | q1 += q1 & 1; | |
| 745 | } | |
| 746 | } | |
| 747 | } | |
| 748 | ||
| 749 | ix0 = (q >> 1) + 0x3FE00000; | |
| 750 | ix1 = q1 >> 1; | |
| 751 | if (q & 1 != 0) { | |
| 752 | ix1 |= 0x80000000; | |
| 753 | } | |
| 754 | ||
| 755 | // NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same | |
| 756 | // behaviour at least. | |
| 757 | var iix0 = @intCast(i32, ix0); | |
| 758 | iix0 = iix0 +% (m << 20); | |
| 759 | ||
| 760 | const uz = (@intCast(u64, iix0) << 32) | ix1; | |
| 761 | return @bitCast(f64, uz); | |
| 762 | } | |
| 763 | ||
| 764 | test "sqrt" { | |
| 765 | const V = [_]f64{ | |
| 766 | 0.0, | |
| 767 | 4.089288054930154, | |
| 768 | 7.538757127071935, | |
| 769 | 8.97780793672623, | |
| 770 | 5.304443821913729, | |
| 771 | 5.682408965311888, | |
| 772 | 0.5846878579110049, | |
| 773 | 3.650338664297043, | |
| 774 | 0.3178091951800732, | |
| 775 | 7.1505232436382835, | |
| 776 | 3.6589165881946464, | |
| 777 | }; | |
| 778 | ||
| 779 | // Note that @sqrt will either generate the sqrt opcode (if supported by the | |
| 780 | // target ISA) or a call to `sqrtf` otherwise. | |
| 781 | for (V) |val| | |
| 782 | try std.testing.expectEqual(@sqrt(val), sqrt(val)); | |
| 783 | } | |
| 784 | ||
| 785 | test "sqrt special" { | |
| 786 | try std.testing.expect(std.math.isPositiveInf(sqrt(std.math.inf(f64)))); | |
| 787 | try std.testing.expect(sqrt(0.0) == 0.0); | |
| 788 | try std.testing.expect(sqrt(-0.0) == -0.0); | |
| 789 | try std.testing.expect(isNan(sqrt(-1.0))); | |
| 790 | try std.testing.expect(isNan(sqrt(std.math.nan(f64)))); | |
| 791 | } | |
| 792 | ||
| 793 | fn sqrtf(x: f32) callconv(.C) f32 { | |
| 794 | const tiny: f32 = 1.0e-30; | |
| 795 | const sign: i32 = @bitCast(i32, @as(u32, 0x80000000)); | |
| 796 | var ix: i32 = @bitCast(i32, x); | |
| 797 | ||
| 798 | if ((ix & 0x7F800000) == 0x7F800000) { | |
| 799 | return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan | |
| 800 | } | |
| 801 | ||
| 802 | // zero | |
| 803 | if (ix <= 0) { | |
| 804 | if (ix & ~sign == 0) { | |
| 805 | return x; // sqrt (+-0) = +-0 | |
| 806 | } | |
| 807 | if (ix < 0) { | |
| 808 | return math.snan(f32); | |
| 809 | } | |
| 810 | } | |
| 811 | ||
| 812 | // normalize | |
| 813 | var m = ix >> 23; | |
| 814 | if (m == 0) { | |
| 815 | // subnormal | |
| 816 | var i: i32 = 0; | |
| 817 | while (ix & 0x00800000 == 0) : (i += 1) { | |
| 818 | ix <<= 1; | |
| 819 | } | |
| 820 | m -= i - 1; | |
| 821 | } | |
| 822 | ||
| 823 | m -= 127; // unbias exponent | |
| 824 | ix = (ix & 0x007FFFFF) | 0x00800000; | |
| 825 | ||
| 826 | if (m & 1 != 0) { // odd m, double x to even | |
| 827 | ix += ix; | |
| 828 | } | |
| 829 | ||
| 830 | m >>= 1; // m = [m / 2] | |
| 831 | ||
| 832 | // sqrt(x) bit by bit | |
| 833 | ix += ix; | |
| 834 | var q: i32 = 0; // q = sqrt(x) | |
| 835 | var s: i32 = 0; | |
| 836 | var r: i32 = 0x01000000; // r = moving bit right -> left | |
| 837 | ||
| 838 | while (r != 0) { | |
| 839 | const t = s + r; | |
| 840 | if (t <= ix) { | |
| 841 | s = t + r; | |
| 842 | ix -= t; | |
| 843 | q += r; | |
| 844 | } | |
| 845 | ix += ix; | |
| 846 | r >>= 1; | |
| 847 | } | |
| 848 | ||
| 849 | // floating add to find rounding direction | |
| 850 | if (ix != 0) { | |
| 851 | var z = 1.0 - tiny; // inexact | |
| 852 | if (z >= 1.0) { | |
| 853 | z = 1.0 + tiny; | |
| 854 | if (z > 1.0) { | |
| 855 | q += 2; | |
| 856 | } else { | |
| 857 | if (q & 1 != 0) { | |
| 858 | q += 1; | |
| 859 | } | |
| 860 | } | |
| 861 | } | |
| 862 | } | |
| 863 | ||
| 864 | ix = (q >> 1) + 0x3f000000; | |
| 865 | ix += m << 23; | |
| 866 | return @bitCast(f32, ix); | |
| 867 | } | |
| 868 | ||
| 869 | test "sqrtf" { | |
| 870 | const V = [_]f32{ | |
| 871 | 0.0, | |
| 872 | 4.089288054930154, | |
| 873 | 7.538757127071935, | |
| 874 | 8.97780793672623, | |
| 875 | 5.304443821913729, | |
| 876 | 5.682408965311888, | |
| 877 | 0.5846878579110049, | |
| 878 | 3.650338664297043, | |
| 879 | 0.3178091951800732, | |
| 880 | 7.1505232436382835, | |
| 881 | 3.6589165881946464, | |
| 882 | }; | |
| 883 | ||
| 884 | // Note that @sqrt will either generate the sqrt opcode (if supported by the | |
| 885 | // target ISA) or a call to `sqrtf` otherwise. | |
| 886 | for (V) |val| | |
| 887 | try std.testing.expectEqual(@sqrt(val), sqrtf(val)); | |
| 888 | } | |
| 889 | ||
| 890 | test "sqrtf special" { | |
| 891 | try std.testing.expect(std.math.isPositiveInf(sqrtf(std.math.inf(f32)))); | |
| 892 | try std.testing.expect(sqrtf(0.0) == 0.0); | |
| 893 | try std.testing.expect(sqrtf(-0.0) == -0.0); | |
| 894 | try std.testing.expect(isNan(sqrtf(-1.0))); | |
| 895 | try std.testing.expect(isNan(sqrtf(std.math.nan(f32)))); | |
| 896 | } | |
| 897 | ||
| 898 | 307 | // TODO we should be able to put this directly in std/linux/x86_64.zig but |
| 899 | 308 | // it causes a segfault in release mode. this is a workaround of calling it |
| 900 | 309 | // across .o file boundaries. fix comptime @ptrCast of nakedcc functions. |
lib/std/special/compiler_rt.zig+53-92| ... | ... | @@ -19,9 +19,6 @@ const strong_linkage = if (is_test) |
| 19 | 19 | else |
| 20 | 20 | std.builtin.GlobalLinkage.Strong; |
| 21 | 21 | |
| 22 | const long_double_is_f80 = builtin.target.longDoubleIs(f80); | |
| 23 | const long_double_is_f128 = builtin.target.longDoubleIs(f128); | |
| 24 | ||
| 25 | 22 | comptime { |
| 26 | 23 | // These files do their own comptime exporting logic. |
| 27 | 24 | _ = @import("compiler_rt/atomics.zig"); |
| ... | ... | @@ -726,42 +723,25 @@ comptime { |
| 726 | 723 | @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage }); |
| 727 | 724 | } |
| 728 | 725 | |
| 729 | if (!is_test) { | |
| 730 | if (long_double_is_f80) { | |
| 731 | @export(fmodx, .{ .name = "fmodl", .linkage = linkage }); | |
| 732 | } else if (long_double_is_f128) { | |
| 733 | @export(fmodq, .{ .name = "fmodl", .linkage = linkage }); | |
| 734 | } else { | |
| 735 | @export(fmodl, .{ .name = "fmodl", .linkage = linkage }); | |
| 736 | } | |
| 737 | if (long_double_is_f80 or builtin.zig_backend == .stage1) { | |
| 738 | // TODO: https://github.com/ziglang/zig/issues/11161 | |
| 739 | @export(fmodx, .{ .name = "fmodx", .linkage = linkage }); | |
| 740 | } | |
| 741 | @export(fmodq, .{ .name = "fmodq", .linkage = linkage }); | |
| 742 | ||
| 743 | @export(floorf, .{ .name = "floorf", .linkage = linkage }); | |
| 744 | @export(floor, .{ .name = "floor", .linkage = linkage }); | |
| 745 | @export(floorl, .{ .name = "floorl", .linkage = linkage }); | |
| 746 | ||
| 747 | @export(ceilf, .{ .name = "ceilf", .linkage = linkage }); | |
| 748 | @export(ceil, .{ .name = "ceil", .linkage = linkage }); | |
| 749 | @export(ceill, .{ .name = "ceill", .linkage = linkage }); | |
| 750 | ||
| 751 | @export(fma, .{ .name = "fma", .linkage = linkage }); | |
| 752 | @export(fmaf, .{ .name = "fmaf", .linkage = linkage }); | |
| 753 | @export(fmal, .{ .name = "fmal", .linkage = linkage }); | |
| 754 | if (long_double_is_f80) { | |
| 755 | @export(fmal, .{ .name = "__fmax", .linkage = linkage }); | |
| 756 | } else { | |
| 757 | @export(__fmax, .{ .name = "__fmax", .linkage = linkage }); | |
| 758 | } | |
| 759 | if (long_double_is_f128) { | |
| 760 | @export(fmal, .{ .name = "fmaq", .linkage = linkage }); | |
| 761 | } else { | |
| 762 | @export(fmaq, .{ .name = "fmaq", .linkage = linkage }); | |
| 763 | } | |
| 764 | } | |
| 726 | mathExport("ceil", @import("./compiler_rt/ceil.zig")); | |
| 727 | mathExport("cos", @import("./compiler_rt/cos.zig")); | |
| 728 | mathExport("exp", @import("./compiler_rt/exp.zig")); | |
| 729 | mathExport("exp2", @import("./compiler_rt/exp2.zig")); | |
| 730 | mathExport("fabs", @import("./compiler_rt/fabs.zig")); | |
| 731 | mathExport("floor", @import("./compiler_rt/floor.zig")); | |
| 732 | mathExport("fma", @import("./compiler_rt/fma.zig")); | |
| 733 | mathExport("fmax", @import("./compiler_rt/fmax.zig")); | |
| 734 | mathExport("fmin", @import("./compiler_rt/fmin.zig")); | |
| 735 | mathExport("fmod", @import("./compiler_rt/fmod.zig")); | |
| 736 | mathExport("log", @import("./compiler_rt/log.zig")); | |
| 737 | mathExport("log10", @import("./compiler_rt/log10.zig")); | |
| 738 | mathExport("log2", @import("./compiler_rt/log2.zig")); | |
| 739 | mathExport("round", @import("./compiler_rt/round.zig")); | |
| 740 | mathExport("sin", @import("./compiler_rt/sin.zig")); | |
| 741 | mathExport("sincos", @import("./compiler_rt/sincos.zig")); | |
| 742 | mathExport("sqrt", @import("./compiler_rt/sqrt.zig")); | |
| 743 | mathExport("tan", @import("./compiler_rt/tan.zig")); | |
| 744 | mathExport("trunc", @import("./compiler_rt/trunc.zig")); | |
| 765 | 745 | |
| 766 | 746 | if (arch.isSPARC()) { |
| 767 | 747 | // SPARC systems use a different naming scheme |
| ... | ... | @@ -842,63 +822,44 @@ comptime { |
| 842 | 822 | @export(__unordtf2, .{ .name = "__unordkf2", .linkage = linkage }); |
| 843 | 823 | |
| 844 | 824 | // LLVM PPC backend lowers f128 fma to `fmaf128`. |
| 845 | @export(fmal, .{ .name = "fmaf128", .linkage = linkage }); | |
| 825 | const fmaq = @import("./compiler_rt/fma.zig").fmaq; | |
| 826 | @export(fmaq, .{ .name = "fmaf128", .linkage = linkage }); | |
| 846 | 827 | } |
| 847 | 828 | } |
| 848 | 829 | |
| 849 | const math = std.math; | |
| 850 | ||
| 851 | fn fmaf(a: f32, b: f32, c: f32) callconv(.C) f32 { | |
| 852 | return math.fma(f32, a, b, c); | |
| 853 | } | |
| 854 | fn fma(a: f64, b: f64, c: f64) callconv(.C) f64 { | |
| 855 | return math.fma(f64, a, b, c); | |
| 856 | } | |
| 857 | fn __fmax(a: f80, b: f80, c: f80) callconv(.C) f80 { | |
| 858 | return math.fma(f80, a, b, c); | |
| 859 | } | |
| 860 | fn fmaq(a: f128, b: f128, c: f128) callconv(.C) f128 { | |
| 861 | return math.fma(f128, a, b, c); | |
| 862 | } | |
| 863 | fn fmal(a: c_longdouble, b: c_longdouble, c: c_longdouble) callconv(.C) c_longdouble { | |
| 864 | return math.fma(c_longdouble, a, b, c); | |
| 865 | } | |
| 866 | ||
| 867 | // TODO add intrinsics for these (and probably the double version too) | |
| 868 | // and have the math stuff use the intrinsic. same as @mod and @rem | |
| 869 | fn floorf(x: f32) callconv(.C) f32 { | |
| 870 | return math.floor(x); | |
| 871 | } | |
| 872 | fn floor(x: f64) callconv(.C) f64 { | |
| 873 | return math.floor(x); | |
| 874 | } | |
| 875 | fn floorl(x: c_longdouble) callconv(.C) c_longdouble { | |
| 876 | if (!long_double_is_f128) { | |
| 877 | @panic("TODO implement this"); | |
| 878 | } | |
| 879 | return math.floor(x); | |
| 880 | } | |
| 881 | ||
| 882 | fn ceilf(x: f32) callconv(.C) f32 { | |
| 883 | return math.ceil(x); | |
| 884 | } | |
| 885 | fn ceil(x: f64) callconv(.C) f64 { | |
| 886 | return math.ceil(x); | |
| 887 | } | |
| 888 | fn ceill(x: c_longdouble) callconv(.C) c_longdouble { | |
| 889 | if (!long_double_is_f128) { | |
| 890 | @panic("TODO implement this"); | |
| 891 | } | |
| 892 | return math.ceil(x); | |
| 893 | } | |
| 894 | ||
| 895 | const fmodq = @import("compiler_rt/fmodq.zig").fmodq; | |
| 896 | const fmodx = @import("compiler_rt/fmodx.zig").fmodx; | |
| 897 | fn fmodl(x: c_longdouble, y: c_longdouble) callconv(.C) c_longdouble { | |
| 898 | if (!long_double_is_f128) { | |
| 899 | @panic("TODO implement this"); | |
| 830 | inline fn mathExport(double_name: []const u8, comptime import: type) void { | |
| 831 | const half_name = "__" ++ double_name ++ "h"; | |
| 832 | const half_fn = @field(import, half_name); | |
| 833 | const float_name = double_name ++ "f"; | |
| 834 | const float_fn = @field(import, float_name); | |
| 835 | const double_fn = @field(import, double_name); | |
| 836 | const long_double_name = double_name ++ "l"; | |
| 837 | const xf80_name = "__" ++ double_name ++ "x"; | |
| 838 | const xf80_fn = @field(import, xf80_name); | |
| 839 | const quad_name = double_name ++ "q"; | |
| 840 | const quad_fn = @field(import, quad_name); | |
| 841 | ||
| 842 | @export(half_fn, .{ .name = half_name, .linkage = linkage }); | |
| 843 | @export(float_fn, .{ .name = float_name, .linkage = linkage }); | |
| 844 | @export(double_fn, .{ .name = double_name, .linkage = linkage }); | |
| 845 | @export(xf80_fn, .{ .name = xf80_name, .linkage = linkage }); | |
| 846 | @export(quad_fn, .{ .name = quad_name, .linkage = linkage }); | |
| 847 | ||
| 848 | const pairs = .{ | |
| 849 | .{ f16, half_fn }, | |
| 850 | .{ f32, float_fn }, | |
| 851 | .{ f64, double_fn }, | |
| 852 | .{ f80, xf80_fn }, | |
| 853 | .{ f128, quad_fn }, | |
| 854 | }; | |
| 855 | ||
| 856 | inline for (pairs) |pair| { | |
| 857 | const F = pair[0]; | |
| 858 | const func = pair[1]; | |
| 859 | if (builtin.target.longDoubleIs(F)) { | |
| 860 | @export(func, .{ .name = long_double_name, .linkage = linkage }); | |
| 861 | } | |
| 900 | 862 | } |
| 901 | return @floatCast(c_longdouble, fmodq(x, y)); | |
| 902 | 863 | } |
| 903 | 864 | |
| 904 | 865 | // Avoid dragging in the runtime safety mechanisms into this .o file, |
lib/std/special/compiler_rt/ceil.zig created+154| ... | ... | @@ -0,0 +1,154 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | pub fn __ceilh(x: f16) callconv(.C) f16 { | |
| 12 | // TODO: more efficient implementation | |
| 13 | return @floatCast(f16, ceilf(x)); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn ceilf(x: f32) callconv(.C) f32 { | |
| 17 | var u = @bitCast(u32, x); | |
| 18 | var e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F; | |
| 19 | var m: u32 = undefined; | |
| 20 | ||
| 21 | // TODO: Shouldn't need this explicit check. | |
| 22 | if (x == 0.0) { | |
| 23 | return x; | |
| 24 | } | |
| 25 | ||
| 26 | if (e >= 23) { | |
| 27 | return x; | |
| 28 | } else if (e >= 0) { | |
| 29 | m = @as(u32, 0x007FFFFF) >> @intCast(u5, e); | |
| 30 | if (u & m == 0) { | |
| 31 | return x; | |
| 32 | } | |
| 33 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 34 | if (u >> 31 == 0) { | |
| 35 | u += m; | |
| 36 | } | |
| 37 | u &= ~m; | |
| 38 | return @bitCast(f32, u); | |
| 39 | } else { | |
| 40 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 41 | if (u >> 31 != 0) { | |
| 42 | return -0.0; | |
| 43 | } else { | |
| 44 | return 1.0; | |
| 45 | } | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | pub fn ceil(x: f64) callconv(.C) f64 { | |
| 50 | const f64_toint = 1.0 / math.floatEps(f64); | |
| 51 | ||
| 52 | const u = @bitCast(u64, x); | |
| 53 | const e = (u >> 52) & 0x7FF; | |
| 54 | var y: f64 = undefined; | |
| 55 | ||
| 56 | if (e >= 0x3FF + 52 or x == 0) { | |
| 57 | return x; | |
| 58 | } | |
| 59 | ||
| 60 | if (u >> 63 != 0) { | |
| 61 | y = x - f64_toint + f64_toint - x; | |
| 62 | } else { | |
| 63 | y = x + f64_toint - f64_toint - x; | |
| 64 | } | |
| 65 | ||
| 66 | if (e <= 0x3FF - 1) { | |
| 67 | math.doNotOptimizeAway(y); | |
| 68 | if (u >> 63 != 0) { | |
| 69 | return -0.0; | |
| 70 | } else { | |
| 71 | return 1.0; | |
| 72 | } | |
| 73 | } else if (y < 0) { | |
| 74 | return x + y + 1; | |
| 75 | } else { | |
| 76 | return x + y; | |
| 77 | } | |
| 78 | } | |
| 79 | ||
| 80 | pub fn __ceilx(x: f80) callconv(.C) f80 { | |
| 81 | // TODO: more efficient implementation | |
| 82 | return @floatCast(f80, ceilq(x)); | |
| 83 | } | |
| 84 | ||
| 85 | pub fn ceilq(x: f128) callconv(.C) f128 { | |
| 86 | const f128_toint = 1.0 / math.floatEps(f128); | |
| 87 | ||
| 88 | const u = @bitCast(u128, x); | |
| 89 | const e = (u >> 112) & 0x7FFF; | |
| 90 | var y: f128 = undefined; | |
| 91 | ||
| 92 | if (e >= 0x3FFF + 112 or x == 0) return x; | |
| 93 | ||
| 94 | if (u >> 127 != 0) { | |
| 95 | y = x - f128_toint + f128_toint - x; | |
| 96 | } else { | |
| 97 | y = x + f128_toint - f128_toint - x; | |
| 98 | } | |
| 99 | ||
| 100 | if (e <= 0x3FFF - 1) { | |
| 101 | math.doNotOptimizeAway(y); | |
| 102 | if (u >> 127 != 0) { | |
| 103 | return -0.0; | |
| 104 | } else { | |
| 105 | return 1.0; | |
| 106 | } | |
| 107 | } else if (y < 0) { | |
| 108 | return x + y + 1; | |
| 109 | } else { | |
| 110 | return x + y; | |
| 111 | } | |
| 112 | } | |
| 113 | ||
| 114 | test "ceil32" { | |
| 115 | try expect(ceilf(1.3) == 2.0); | |
| 116 | try expect(ceilf(-1.3) == -1.0); | |
| 117 | try expect(ceilf(0.2) == 1.0); | |
| 118 | } | |
| 119 | ||
| 120 | test "ceil64" { | |
| 121 | try expect(ceil(1.3) == 2.0); | |
| 122 | try expect(ceil(-1.3) == -1.0); | |
| 123 | try expect(ceil(0.2) == 1.0); | |
| 124 | } | |
| 125 | ||
| 126 | test "ceil128" { | |
| 127 | try expect(ceilq(1.3) == 2.0); | |
| 128 | try expect(ceilq(-1.3) == -1.0); | |
| 129 | try expect(ceilq(0.2) == 1.0); | |
| 130 | } | |
| 131 | ||
| 132 | test "ceil32.special" { | |
| 133 | try expect(ceilf(0.0) == 0.0); | |
| 134 | try expect(ceilf(-0.0) == -0.0); | |
| 135 | try expect(math.isPositiveInf(ceilf(math.inf(f32)))); | |
| 136 | try expect(math.isNegativeInf(ceilf(-math.inf(f32)))); | |
| 137 | try expect(math.isNan(ceilf(math.nan(f32)))); | |
| 138 | } | |
| 139 | ||
| 140 | test "ceil64.special" { | |
| 141 | try expect(ceil(0.0) == 0.0); | |
| 142 | try expect(ceil(-0.0) == -0.0); | |
| 143 | try expect(math.isPositiveInf(ceil(math.inf(f64)))); | |
| 144 | try expect(math.isNegativeInf(ceil(-math.inf(f64)))); | |
| 145 | try expect(math.isNan(ceil(math.nan(f64)))); | |
| 146 | } | |
| 147 | ||
| 148 | test "ceil128.special" { | |
| 149 | try expect(ceilq(0.0) == 0.0); | |
| 150 | try expect(ceilq(-0.0) == -0.0); | |
| 151 | try expect(math.isPositiveInf(ceilq(math.inf(f128)))); | |
| 152 | try expect(math.isNegativeInf(ceilq(-math.inf(f128)))); | |
| 153 | try expect(math.isNan(ceilq(math.nan(f128)))); | |
| 154 | } |
lib/std/special/compiler_rt/cos.zig created+144| ... | ... | @@ -0,0 +1,144 @@ |
| 1 | const std = @import("std"); | |
| 2 | const math = std.math; | |
| 3 | const expect = std.testing.expect; | |
| 4 | ||
| 5 | const kernel = @import("trig.zig"); | |
| 6 | const rem_pio2 = @import("rem_pio2.zig").rem_pio2; | |
| 7 | const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; | |
| 8 | ||
| 9 | pub fn __cosh(a: f16) callconv(.C) f16 { | |
| 10 | // TODO: more efficient implementation | |
| 11 | return @floatCast(f16, cosf(a)); | |
| 12 | } | |
| 13 | ||
| 14 | pub fn cosf(x: f32) callconv(.C) f32 { | |
| 15 | // Small multiples of pi/2 rounded to double precision. | |
| 16 | const c1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 | |
| 17 | const c2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 | |
| 18 | const c3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2 | |
| 19 | const c4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18 | |
| 20 | ||
| 21 | var ix = @bitCast(u32, x); | |
| 22 | const sign = ix >> 31 != 0; | |
| 23 | ix &= 0x7fffffff; | |
| 24 | ||
| 25 | if (ix <= 0x3f490fda) { // |x| ~<= pi/4 | |
| 26 | if (ix < 0x39800000) { // |x| < 2**-12 | |
| 27 | // raise inexact if x != 0 | |
| 28 | math.doNotOptimizeAway(x + 0x1p120); | |
| 29 | return 1.0; | |
| 30 | } | |
| 31 | return kernel.__cosdf(x); | |
| 32 | } | |
| 33 | if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4 | |
| 34 | if (ix > 0x4016cbe3) { // |x| ~> 3*pi/4 | |
| 35 | return -kernel.__cosdf(if (sign) x + c2pio2 else x - c2pio2); | |
| 36 | } else { | |
| 37 | if (sign) { | |
| 38 | return kernel.__sindf(x + c1pio2); | |
| 39 | } else { | |
| 40 | return kernel.__sindf(c1pio2 - x); | |
| 41 | } | |
| 42 | } | |
| 43 | } | |
| 44 | if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4 | |
| 45 | if (ix > 0x40afeddf) { // |x| ~> 7*pi/4 | |
| 46 | return kernel.__cosdf(if (sign) x + c4pio2 else x - c4pio2); | |
| 47 | } else { | |
| 48 | if (sign) { | |
| 49 | return kernel.__sindf(-x - c3pio2); | |
| 50 | } else { | |
| 51 | return kernel.__sindf(x - c3pio2); | |
| 52 | } | |
| 53 | } | |
| 54 | } | |
| 55 | ||
| 56 | // cos(Inf or NaN) is NaN | |
| 57 | if (ix >= 0x7f800000) { | |
| 58 | return x - x; | |
| 59 | } | |
| 60 | ||
| 61 | var y: f64 = undefined; | |
| 62 | const n = rem_pio2f(x, &y); | |
| 63 | return switch (n & 3) { | |
| 64 | 0 => kernel.__cosdf(y), | |
| 65 | 1 => kernel.__sindf(-y), | |
| 66 | 2 => -kernel.__cosdf(y), | |
| 67 | else => kernel.__sindf(y), | |
| 68 | }; | |
| 69 | } | |
| 70 | ||
| 71 | pub fn cos(x: f64) callconv(.C) f64 { | |
| 72 | var ix = @bitCast(u64, x) >> 32; | |
| 73 | ix &= 0x7fffffff; | |
| 74 | ||
| 75 | // |x| ~< pi/4 | |
| 76 | if (ix <= 0x3fe921fb) { | |
| 77 | if (ix < 0x3e46a09e) { // |x| < 2**-27 * sqrt(2) | |
| 78 | // raise inexact if x!=0 | |
| 79 | math.doNotOptimizeAway(x + 0x1p120); | |
| 80 | return 1.0; | |
| 81 | } | |
| 82 | return kernel.__cos(x, 0); | |
| 83 | } | |
| 84 | ||
| 85 | // cos(Inf or NaN) is NaN | |
| 86 | if (ix >= 0x7ff00000) { | |
| 87 | return x - x; | |
| 88 | } | |
| 89 | ||
| 90 | var y: [2]f64 = undefined; | |
| 91 | const n = rem_pio2(x, &y); | |
| 92 | return switch (n & 3) { | |
| 93 | 0 => kernel.__cos(y[0], y[1]), | |
| 94 | 1 => -kernel.__sin(y[0], y[1], 1), | |
| 95 | 2 => -kernel.__cos(y[0], y[1]), | |
| 96 | else => kernel.__sin(y[0], y[1], 1), | |
| 97 | }; | |
| 98 | } | |
| 99 | ||
| 100 | pub fn __cosx(a: f80) callconv(.C) f80 { | |
| 101 | // TODO: more efficient implementation | |
| 102 | return @floatCast(f80, cosq(a)); | |
| 103 | } | |
| 104 | ||
| 105 | pub fn cosq(a: f128) callconv(.C) f128 { | |
| 106 | // TODO: more correct implementation | |
| 107 | return cos(@floatCast(f64, a)); | |
| 108 | } | |
| 109 | ||
| 110 | test "cos32" { | |
| 111 | const epsilon = 0.00001; | |
| 112 | ||
| 113 | try expect(math.approxEqAbs(f32, cosf(0.0), 1.0, epsilon)); | |
| 114 | try expect(math.approxEqAbs(f32, cosf(0.2), 0.980067, epsilon)); | |
| 115 | try expect(math.approxEqAbs(f32, cosf(0.8923), 0.627623, epsilon)); | |
| 116 | try expect(math.approxEqAbs(f32, cosf(1.5), 0.070737, epsilon)); | |
| 117 | try expect(math.approxEqAbs(f32, cosf(-1.5), 0.070737, epsilon)); | |
| 118 | try expect(math.approxEqAbs(f32, cosf(37.45), 0.969132, epsilon)); | |
| 119 | try expect(math.approxEqAbs(f32, cosf(89.123), 0.400798, epsilon)); | |
| 120 | } | |
| 121 | ||
| 122 | test "cos64" { | |
| 123 | const epsilon = 0.000001; | |
| 124 | ||
| 125 | try expect(math.approxEqAbs(f64, cos(0.0), 1.0, epsilon)); | |
| 126 | try expect(math.approxEqAbs(f64, cos(0.2), 0.980067, epsilon)); | |
| 127 | try expect(math.approxEqAbs(f64, cos(0.8923), 0.627623, epsilon)); | |
| 128 | try expect(math.approxEqAbs(f64, cos(1.5), 0.070737, epsilon)); | |
| 129 | try expect(math.approxEqAbs(f64, cos(-1.5), 0.070737, epsilon)); | |
| 130 | try expect(math.approxEqAbs(f64, cos(37.45), 0.969132, epsilon)); | |
| 131 | try expect(math.approxEqAbs(f64, cos(89.123), 0.40080, epsilon)); | |
| 132 | } | |
| 133 | ||
| 134 | test "cos32.special" { | |
| 135 | try expect(math.isNan(cosf(math.inf(f32)))); | |
| 136 | try expect(math.isNan(cosf(-math.inf(f32)))); | |
| 137 | try expect(math.isNan(cosf(math.nan(f32)))); | |
| 138 | } | |
| 139 | ||
| 140 | test "cos64.special" { | |
| 141 | try expect(math.isNan(cos(math.inf(f64)))); | |
| 142 | try expect(math.isNan(cos(-math.inf(f64)))); | |
| 143 | try expect(math.isNan(cos(math.nan(f64)))); | |
| 144 | } |
lib/std/special/compiler_rt/divxf3_test.zig+3-3| ... | ... | @@ -30,9 +30,9 @@ fn test__divxf3(a: f80, b: f80) !void { |
| 30 | 30 | const x_minus_eps = @bitCast(f80, (@bitCast(u80, x) - 1) | integerBit); |
| 31 | 31 | |
| 32 | 32 | // Make sure result is more accurate than the adjacent floats |
| 33 | const err_x = std.math.fabs(@mulAdd(f80, x, b, -a)); | |
| 34 | const err_x_plus_eps = std.math.fabs(@mulAdd(f80, x_plus_eps, b, -a)); | |
| 35 | const err_x_minus_eps = std.math.fabs(@mulAdd(f80, x_minus_eps, b, -a)); | |
| 33 | const err_x = @fabs(@mulAdd(f80, x, b, -a)); | |
| 34 | const err_x_plus_eps = @fabs(@mulAdd(f80, x_plus_eps, b, -a)); | |
| 35 | const err_x_minus_eps = @fabs(@mulAdd(f80, x_minus_eps, b, -a)); | |
| 36 | 36 | |
| 37 | 37 | try testing.expect(err_x_minus_eps > err_x); |
| 38 | 38 | try testing.expect(err_x_plus_eps > err_x); |
lib/std/special/compiler_rt/exp.zig created+213| ... | ... | @@ -0,0 +1,213 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/expf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/exp.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | pub fn __exph(a: f16) callconv(.C) f16 { | |
| 12 | // TODO: more efficient implementation | |
| 13 | return @floatCast(f16, expf(a)); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn expf(x_: f32) callconv(.C) f32 { | |
| 17 | const half = [_]f32{ 0.5, -0.5 }; | |
| 18 | const ln2hi = 6.9314575195e-1; | |
| 19 | const ln2lo = 1.4286067653e-6; | |
| 20 | const invln2 = 1.4426950216e+0; | |
| 21 | const P1 = 1.6666625440e-1; | |
| 22 | const P2 = -2.7667332906e-3; | |
| 23 | ||
| 24 | var x = x_; | |
| 25 | var hx = @bitCast(u32, x); | |
| 26 | const sign = @intCast(i32, hx >> 31); | |
| 27 | hx &= 0x7FFFFFFF; | |
| 28 | ||
| 29 | if (math.isNan(x)) { | |
| 30 | return x; | |
| 31 | } | |
| 32 | ||
| 33 | // |x| >= -87.33655 or nan | |
| 34 | if (hx >= 0x42AEAC50) { | |
| 35 | // nan | |
| 36 | if (hx > 0x7F800000) { | |
| 37 | return x; | |
| 38 | } | |
| 39 | // x >= 88.722839 | |
| 40 | if (hx >= 0x42b17218 and sign == 0) { | |
| 41 | return x * 0x1.0p127; | |
| 42 | } | |
| 43 | if (sign != 0) { | |
| 44 | math.doNotOptimizeAway(-0x1.0p-149 / x); // overflow | |
| 45 | // x <= -103.972084 | |
| 46 | if (hx >= 0x42CFF1B5) { | |
| 47 | return 0; | |
| 48 | } | |
| 49 | } | |
| 50 | } | |
| 51 | ||
| 52 | var k: i32 = undefined; | |
| 53 | var hi: f32 = undefined; | |
| 54 | var lo: f32 = undefined; | |
| 55 | ||
| 56 | // |x| > 0.5 * ln2 | |
| 57 | if (hx > 0x3EB17218) { | |
| 58 | // |x| > 1.5 * ln2 | |
| 59 | if (hx > 0x3F851592) { | |
| 60 | k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]); | |
| 61 | } else { | |
| 62 | k = 1 - sign - sign; | |
| 63 | } | |
| 64 | ||
| 65 | const fk = @intToFloat(f32, k); | |
| 66 | hi = x - fk * ln2hi; | |
| 67 | lo = fk * ln2lo; | |
| 68 | x = hi - lo; | |
| 69 | } | |
| 70 | // |x| > 2^(-14) | |
| 71 | else if (hx > 0x39000000) { | |
| 72 | k = 0; | |
| 73 | hi = x; | |
| 74 | lo = 0; | |
| 75 | } else { | |
| 76 | math.doNotOptimizeAway(0x1.0p127 + x); // inexact | |
| 77 | return 1 + x; | |
| 78 | } | |
| 79 | ||
| 80 | const xx = x * x; | |
| 81 | const c = x - xx * (P1 + xx * P2); | |
| 82 | const y = 1 + (x * c / (2 - c) - lo + hi); | |
| 83 | ||
| 84 | if (k == 0) { | |
| 85 | return y; | |
| 86 | } else { | |
| 87 | return math.scalbn(y, k); | |
| 88 | } | |
| 89 | } | |
| 90 | ||
| 91 | pub fn exp(x_: f64) callconv(.C) f64 { | |
| 92 | const half = [_]f64{ 0.5, -0.5 }; | |
| 93 | const ln2hi: f64 = 6.93147180369123816490e-01; | |
| 94 | const ln2lo: f64 = 1.90821492927058770002e-10; | |
| 95 | const invln2: f64 = 1.44269504088896338700e+00; | |
| 96 | const P1: f64 = 1.66666666666666019037e-01; | |
| 97 | const P2: f64 = -2.77777777770155933842e-03; | |
| 98 | const P3: f64 = 6.61375632143793436117e-05; | |
| 99 | const P4: f64 = -1.65339022054652515390e-06; | |
| 100 | const P5: f64 = 4.13813679705723846039e-08; | |
| 101 | ||
| 102 | var x = x_; | |
| 103 | var ux = @bitCast(u64, x); | |
| 104 | var hx = ux >> 32; | |
| 105 | const sign = @intCast(i32, hx >> 31); | |
| 106 | hx &= 0x7FFFFFFF; | |
| 107 | ||
| 108 | if (math.isNan(x)) { | |
| 109 | return x; | |
| 110 | } | |
| 111 | ||
| 112 | // |x| >= 708.39 or nan | |
| 113 | if (hx >= 0x4086232B) { | |
| 114 | // nan | |
| 115 | if (hx > 0x7FF00000) { | |
| 116 | return x; | |
| 117 | } | |
| 118 | if (x > 709.782712893383973096) { | |
| 119 | // overflow if x != inf | |
| 120 | if (!math.isInf(x)) { | |
| 121 | math.raiseOverflow(); | |
| 122 | } | |
| 123 | return math.inf(f64); | |
| 124 | } | |
| 125 | if (x < -708.39641853226410622) { | |
| 126 | // underflow if x != -inf | |
| 127 | // math.doNotOptimizeAway(@as(f32, -0x1.0p-149 / x)); | |
| 128 | if (x < -745.13321910194110842) { | |
| 129 | return 0; | |
| 130 | } | |
| 131 | } | |
| 132 | } | |
| 133 | ||
| 134 | // argument reduction | |
| 135 | var k: i32 = undefined; | |
| 136 | var hi: f64 = undefined; | |
| 137 | var lo: f64 = undefined; | |
| 138 | ||
| 139 | // |x| > 0.5 * ln2 | |
| 140 | if (hx > 0x3FD62E42) { | |
| 141 | // |x| >= 1.5 * ln2 | |
| 142 | if (hx > 0x3FF0A2B2) { | |
| 143 | k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]); | |
| 144 | } else { | |
| 145 | k = 1 - sign - sign; | |
| 146 | } | |
| 147 | ||
| 148 | const dk = @intToFloat(f64, k); | |
| 149 | hi = x - dk * ln2hi; | |
| 150 | lo = dk * ln2lo; | |
| 151 | x = hi - lo; | |
| 152 | } | |
| 153 | // |x| > 2^(-28) | |
| 154 | else if (hx > 0x3E300000) { | |
| 155 | k = 0; | |
| 156 | hi = x; | |
| 157 | lo = 0; | |
| 158 | } else { | |
| 159 | // inexact if x != 0 | |
| 160 | // math.doNotOptimizeAway(0x1.0p1023 + x); | |
| 161 | return 1 + x; | |
| 162 | } | |
| 163 | ||
| 164 | const xx = x * x; | |
| 165 | const c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); | |
| 166 | const y = 1 + (x * c / (2 - c) - lo + hi); | |
| 167 | ||
| 168 | if (k == 0) { | |
| 169 | return y; | |
| 170 | } else { | |
| 171 | return math.scalbn(y, k); | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | pub fn __expx(a: f80) callconv(.C) f80 { | |
| 176 | // TODO: more efficient implementation | |
| 177 | return @floatCast(f80, expq(a)); | |
| 178 | } | |
| 179 | ||
| 180 | pub fn expq(a: f128) callconv(.C) f128 { | |
| 181 | // TODO: more correct implementation | |
| 182 | return exp(@floatCast(f64, a)); | |
| 183 | } | |
| 184 | ||
| 185 | test "exp32" { | |
| 186 | const epsilon = 0.000001; | |
| 187 | ||
| 188 | try expect(expf(0.0) == 1.0); | |
| 189 | try expect(math.approxEqAbs(f32, expf(0.0), 1.0, epsilon)); | |
| 190 | try expect(math.approxEqAbs(f32, expf(0.2), 1.221403, epsilon)); | |
| 191 | try expect(math.approxEqAbs(f32, expf(0.8923), 2.440737, epsilon)); | |
| 192 | try expect(math.approxEqAbs(f32, expf(1.5), 4.481689, epsilon)); | |
| 193 | } | |
| 194 | ||
| 195 | test "exp64" { | |
| 196 | const epsilon = 0.000001; | |
| 197 | ||
| 198 | try expect(exp(0.0) == 1.0); | |
| 199 | try expect(math.approxEqAbs(f64, exp(0.0), 1.0, epsilon)); | |
| 200 | try expect(math.approxEqAbs(f64, exp(0.2), 1.221403, epsilon)); | |
| 201 | try expect(math.approxEqAbs(f64, exp(0.8923), 2.440737, epsilon)); | |
| 202 | try expect(math.approxEqAbs(f64, exp(1.5), 4.481689, epsilon)); | |
| 203 | } | |
| 204 | ||
| 205 | test "exp32.special" { | |
| 206 | try expect(math.isPositiveInf(expf(math.inf(f32)))); | |
| 207 | try expect(math.isNan(expf(math.nan(f32)))); | |
| 208 | } | |
| 209 | ||
| 210 | test "exp64.special" { | |
| 211 | try expect(math.isPositiveInf(exp(math.inf(f64)))); | |
| 212 | try expect(math.isNan(exp(math.nan(f64)))); | |
| 213 | } |
lib/std/special/compiler_rt/exp2.zig created+461| ... | ... | @@ -0,0 +1,461 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/exp2f.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/exp2.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | pub fn __exp2h(x: f16) callconv(.C) f16 { | |
| 12 | // TODO: more efficient implementation | |
| 13 | return @floatCast(f16, exp2f(x)); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn exp2f(x: f32) callconv(.C) f32 { | |
| 17 | const tblsiz = @intCast(u32, exp2ft.len); | |
| 18 | const redux: f32 = 0x1.8p23 / @intToFloat(f32, tblsiz); | |
| 19 | const P1: f32 = 0x1.62e430p-1; | |
| 20 | const P2: f32 = 0x1.ebfbe0p-3; | |
| 21 | const P3: f32 = 0x1.c6b348p-5; | |
| 22 | const P4: f32 = 0x1.3b2c9cp-7; | |
| 23 | ||
| 24 | var u = @bitCast(u32, x); | |
| 25 | const ix = u & 0x7FFFFFFF; | |
| 26 | ||
| 27 | // |x| > 126 | |
| 28 | if (ix > 0x42FC0000) { | |
| 29 | // nan | |
| 30 | if (ix > 0x7F800000) { | |
| 31 | return x; | |
| 32 | } | |
| 33 | // x >= 128 | |
| 34 | if (u >= 0x43000000 and u < 0x80000000) { | |
| 35 | return x * 0x1.0p127; | |
| 36 | } | |
| 37 | // x < -126 | |
| 38 | if (u >= 0x80000000) { | |
| 39 | if (u >= 0xC3160000 or u & 0x000FFFF != 0) { | |
| 40 | math.doNotOptimizeAway(-0x1.0p-149 / x); | |
| 41 | } | |
| 42 | // x <= -150 | |
| 43 | if (u >= 0x3160000) { | |
| 44 | return 0; | |
| 45 | } | |
| 46 | } | |
| 47 | } | |
| 48 | // |x| <= 0x1p-25 | |
| 49 | else if (ix <= 0x33000000) { | |
| 50 | return 1.0 + x; | |
| 51 | } | |
| 52 | ||
| 53 | // NOTE: musl relies on unsafe behaviours which are replicated below | |
| 54 | // (addition/bit-shift overflow). Appears that this produces the | |
| 55 | // intended result but should confirm how GCC/Clang handle this to ensure. | |
| 56 | ||
| 57 | var uf = x + redux; | |
| 58 | var i_0 = @bitCast(u32, uf); | |
| 59 | i_0 +%= tblsiz / 2; | |
| 60 | ||
| 61 | const k = i_0 / tblsiz; | |
| 62 | const uk = @bitCast(f64, @as(u64, 0x3FF + k) << 52); | |
| 63 | i_0 &= tblsiz - 1; | |
| 64 | uf -= redux; | |
| 65 | ||
| 66 | const z: f64 = x - uf; | |
| 67 | var r: f64 = exp2ft[@intCast(usize, i_0)]; | |
| 68 | const t: f64 = r * z; | |
| 69 | r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); | |
| 70 | return @floatCast(f32, r * uk); | |
| 71 | } | |
| 72 | ||
| 73 | pub fn exp2(x: f64) callconv(.C) f64 { | |
| 74 | const tblsiz: u32 = @intCast(u32, exp2dt.len / 2); | |
| 75 | const redux: f64 = 0x1.8p52 / @intToFloat(f64, tblsiz); | |
| 76 | const P1: f64 = 0x1.62e42fefa39efp-1; | |
| 77 | const P2: f64 = 0x1.ebfbdff82c575p-3; | |
| 78 | const P3: f64 = 0x1.c6b08d704a0a6p-5; | |
| 79 | const P4: f64 = 0x1.3b2ab88f70400p-7; | |
| 80 | const P5: f64 = 0x1.5d88003875c74p-10; | |
| 81 | ||
| 82 | const ux = @bitCast(u64, x); | |
| 83 | const ix = @intCast(u32, ux >> 32) & 0x7FFFFFFF; | |
| 84 | ||
| 85 | // TODO: This should be handled beneath. | |
| 86 | if (math.isNan(x)) { | |
| 87 | return math.nan(f64); | |
| 88 | } | |
| 89 | ||
| 90 | // |x| >= 1022 or nan | |
| 91 | if (ix >= 0x408FF000) { | |
| 92 | // x >= 1024 or nan | |
| 93 | if (ix >= 0x40900000 and ux >> 63 == 0) { | |
| 94 | math.raiseOverflow(); | |
| 95 | return math.inf(f64); | |
| 96 | } | |
| 97 | // -inf or -nan | |
| 98 | if (ix >= 0x7FF00000) { | |
| 99 | return -1 / x; | |
| 100 | } | |
| 101 | // x <= -1022 | |
| 102 | if (ux >> 63 != 0) { | |
| 103 | // underflow | |
| 104 | if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) { | |
| 105 | math.doNotOptimizeAway(@floatCast(f32, -0x1.0p-149 / x)); | |
| 106 | } | |
| 107 | if (x <= -1075) { | |
| 108 | return 0; | |
| 109 | } | |
| 110 | } | |
| 111 | } | |
| 112 | // |x| < 0x1p-54 | |
| 113 | else if (ix < 0x3C900000) { | |
| 114 | return 1.0 + x; | |
| 115 | } | |
| 116 | ||
| 117 | // NOTE: musl relies on unsafe behaviours which are replicated below | |
| 118 | // (addition overflow, division truncation, casting). Appears that this | |
| 119 | // produces the intended result but should confirm how GCC/Clang handle this | |
| 120 | // to ensure. | |
| 121 | ||
| 122 | // reduce x | |
| 123 | var uf: f64 = x + redux; | |
| 124 | // NOTE: musl performs an implicit 64-bit to 32-bit u32 truncation here | |
| 125 | var i_0: u32 = @truncate(u32, @bitCast(u64, uf)); | |
| 126 | i_0 +%= tblsiz / 2; | |
| 127 | ||
| 128 | const k: u32 = i_0 / tblsiz * tblsiz; | |
| 129 | const ik: i32 = @divTrunc(@bitCast(i32, k), tblsiz); | |
| 130 | i_0 %= tblsiz; | |
| 131 | uf -= redux; | |
| 132 | ||
| 133 | // r = exp2(y) = exp2t[i_0] * p(z - eps[i]) | |
| 134 | var z: f64 = x - uf; | |
| 135 | const t: f64 = exp2dt[@intCast(usize, 2 * i_0)]; | |
| 136 | z -= exp2dt[@intCast(usize, 2 * i_0 + 1)]; | |
| 137 | const r: f64 = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); | |
| 138 | ||
| 139 | return math.scalbn(r, ik); | |
| 140 | } | |
| 141 | ||
| 142 | pub fn __exp2x(x: f80) callconv(.C) f80 { | |
| 143 | // TODO: more efficient implementation | |
| 144 | return @floatCast(f80, exp2q(x)); | |
| 145 | } | |
| 146 | ||
| 147 | pub fn exp2q(x: f128) callconv(.C) f128 { | |
| 148 | // TODO: more correct implementation | |
| 149 | return exp2(@floatCast(f64, x)); | |
| 150 | } | |
| 151 | ||
| 152 | const exp2ft = [_]f64{ | |
| 153 | 0x1.6a09e667f3bcdp-1, | |
| 154 | 0x1.7a11473eb0187p-1, | |
| 155 | 0x1.8ace5422aa0dbp-1, | |
| 156 | 0x1.9c49182a3f090p-1, | |
| 157 | 0x1.ae89f995ad3adp-1, | |
| 158 | 0x1.c199bdd85529cp-1, | |
| 159 | 0x1.d5818dcfba487p-1, | |
| 160 | 0x1.ea4afa2a490dap-1, | |
| 161 | 0x1.0000000000000p+0, | |
| 162 | 0x1.0b5586cf9890fp+0, | |
| 163 | 0x1.172b83c7d517bp+0, | |
| 164 | 0x1.2387a6e756238p+0, | |
| 165 | 0x1.306fe0a31b715p+0, | |
| 166 | 0x1.3dea64c123422p+0, | |
| 167 | 0x1.4bfdad5362a27p+0, | |
| 168 | 0x1.5ab07dd485429p+0, | |
| 169 | }; | |
| 170 | ||
| 171 | const exp2dt = [_]f64{ | |
| 172 | // exp2(z + eps) eps | |
| 173 | 0x1.6a09e667f3d5dp-1, 0x1.9880p-44, | |
| 174 | 0x1.6b052fa751744p-1, 0x1.8000p-50, | |
| 175 | 0x1.6c012750bd9fep-1, -0x1.8780p-45, | |
| 176 | 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46, | |
| 177 | 0x1.6dfb23c651a29p-1, -0x1.8000p-50, | |
| 178 | 0x1.6ef9298593ae3p-1, -0x1.c000p-52, | |
| 179 | 0x1.6ff7df9519386p-1, -0x1.fd80p-45, | |
| 180 | 0x1.70f7466f42da3p-1, -0x1.c880p-45, | |
| 181 | 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46, | |
| 182 | 0x1.72f8286eacf05p-1, -0x1.8300p-44, | |
| 183 | 0x1.73f9a48a58152p-1, -0x1.0c00p-47, | |
| 184 | 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45, | |
| 185 | 0x1.75feb564267f1p-1, 0x1.3e00p-47, | |
| 186 | 0x1.77024b1ab6d48p-1, -0x1.7d00p-45, | |
| 187 | 0x1.780694fde5d38p-1, -0x1.d000p-50, | |
| 188 | 0x1.790b938ac1d00p-1, 0x1.3000p-49, | |
| 189 | 0x1.7a11473eb0178p-1, -0x1.d000p-49, | |
| 190 | 0x1.7b17b0976d060p-1, 0x1.0400p-45, | |
| 191 | 0x1.7c1ed0130c133p-1, 0x1.0000p-53, | |
| 192 | 0x1.7d26a62ff8636p-1, -0x1.6900p-45, | |
| 193 | 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47, | |
| 194 | 0x1.7f3878491c3e8p-1, -0x1.4580p-45, | |
| 195 | 0x1.80427543e1b4ep-1, 0x1.3000p-44, | |
| 196 | 0x1.814d2add1071ap-1, 0x1.f000p-47, | |
| 197 | 0x1.82589994ccd7ep-1, -0x1.1c00p-45, | |
| 198 | 0x1.8364c1eb942d0p-1, 0x1.9d00p-45, | |
| 199 | 0x1.8471a4623cab5p-1, 0x1.7100p-43, | |
| 200 | 0x1.857f4179f5bbcp-1, 0x1.2600p-45, | |
| 201 | 0x1.868d99b4491afp-1, -0x1.2c40p-44, | |
| 202 | 0x1.879cad931a395p-1, -0x1.3000p-45, | |
| 203 | 0x1.88ac7d98a65b8p-1, -0x1.a800p-45, | |
| 204 | 0x1.89bd0a4785800p-1, -0x1.d000p-49, | |
| 205 | 0x1.8ace5422aa223p-1, 0x1.3280p-44, | |
| 206 | 0x1.8be05bad619fap-1, 0x1.2b40p-43, | |
| 207 | 0x1.8cf3216b54383p-1, -0x1.ed00p-45, | |
| 208 | 0x1.8e06a5e08664cp-1, -0x1.0500p-45, | |
| 209 | 0x1.8f1ae99157807p-1, 0x1.8280p-45, | |
| 210 | 0x1.902fed0282c0ep-1, -0x1.cb00p-46, | |
| 211 | 0x1.9145b0b91ff96p-1, -0x1.5e00p-47, | |
| 212 | 0x1.925c353aa2ff9p-1, 0x1.5400p-48, | |
| 213 | 0x1.93737b0cdc64ap-1, 0x1.7200p-46, | |
| 214 | 0x1.948b82b5f98aep-1, -0x1.9000p-47, | |
| 215 | 0x1.95a44cbc852cbp-1, 0x1.5680p-45, | |
| 216 | 0x1.96bdd9a766f21p-1, -0x1.6d00p-44, | |
| 217 | 0x1.97d829fde4e2ap-1, -0x1.1000p-47, | |
| 218 | 0x1.98f33e47a23a3p-1, 0x1.d000p-45, | |
| 219 | 0x1.9a0f170ca0604p-1, -0x1.8a40p-44, | |
| 220 | 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44, | |
| 221 | 0x1.9c49182a3f15bp-1, 0x1.6b80p-45, | |
| 222 | 0x1.9d674194bb8c5p-1, -0x1.c000p-49, | |
| 223 | 0x1.9e86319e3238ep-1, 0x1.7d00p-46, | |
| 224 | 0x1.9fa5e8d07f302p-1, 0x1.6400p-46, | |
| 225 | 0x1.a0c667b5de54dp-1, -0x1.5000p-48, | |
| 226 | 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47, | |
| 227 | 0x1.a309bec4a2e27p-1, 0x1.ad80p-45, | |
| 228 | 0x1.a42c980460a5dp-1, -0x1.af00p-46, | |
| 229 | 0x1.a5503b23e259bp-1, 0x1.b600p-47, | |
| 230 | 0x1.a674a8af46213p-1, 0x1.8880p-44, | |
| 231 | 0x1.a799e1330b3a7p-1, 0x1.1200p-46, | |
| 232 | 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47, | |
| 233 | 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45, | |
| 234 | 0x1.ab0e521356fb8p-1, 0x1.b700p-45, | |
| 235 | 0x1.ac36bbfd3f381p-1, 0x1.9000p-50, | |
| 236 | 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49, | |
| 237 | 0x1.ae89f995ad2a3p-1, -0x1.c900p-45, | |
| 238 | 0x1.afb4ce622f367p-1, 0x1.6500p-46, | |
| 239 | 0x1.b0e07298db790p-1, 0x1.fd40p-45, | |
| 240 | 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46, | |
| 241 | 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43, | |
| 242 | 0x1.b468415b747e7p-1, -0x1.8380p-44, | |
| 243 | 0x1.b59728de5593ap-1, 0x1.8000p-54, | |
| 244 | 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47, | |
| 245 | 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50, | |
| 246 | 0x1.b928cf22749b2p-1, -0x1.4c00p-47, | |
| 247 | 0x1.ba5b030a10603p-1, -0x1.d700p-47, | |
| 248 | 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47, | |
| 249 | 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47, | |
| 250 | 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46, | |
| 251 | 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46, | |
| 252 | 0x1.c06286141b2e9p-1, -0x1.1400p-46, | |
| 253 | 0x1.c199bdd8552e0p-1, 0x1.be00p-47, | |
| 254 | 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47, | |
| 255 | 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47, | |
| 256 | 0x1.c544778fafd15p-1, 0x1.9660p-44, | |
| 257 | 0x1.c67f12e57d0cbp-1, -0x1.a100p-46, | |
| 258 | 0x1.c7ba88988c1b6p-1, -0x1.8458p-42, | |
| 259 | 0x1.c8f6d9406e733p-1, -0x1.a480p-46, | |
| 260 | 0x1.ca3405751c4dfp-1, 0x1.b000p-51, | |
| 261 | 0x1.cb720dcef9094p-1, 0x1.1400p-47, | |
| 262 | 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48, | |
| 263 | 0x1.cdf0b555dc412p-1, 0x1.3600p-48, | |
| 264 | 0x1.cf3155b5bab3bp-1, -0x1.6900p-47, | |
| 265 | 0x1.d072d4a0789bcp-1, 0x1.9a00p-47, | |
| 266 | 0x1.d1b532b08c8fap-1, -0x1.5e00p-46, | |
| 267 | 0x1.d2f87080d8a85p-1, 0x1.d280p-46, | |
| 268 | 0x1.d43c8eacaa203p-1, 0x1.1a00p-47, | |
| 269 | 0x1.d5818dcfba491p-1, 0x1.f000p-50, | |
| 270 | 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47, | |
| 271 | 0x1.d80e316c9834ep-1, -0x1.cd80p-47, | |
| 272 | 0x1.d955d71ff6090p-1, 0x1.4c00p-48, | |
| 273 | 0x1.da9e603db32aep-1, 0x1.f900p-48, | |
| 274 | 0x1.dbe7cd63a8325p-1, 0x1.9800p-49, | |
| 275 | 0x1.dd321f301b445p-1, -0x1.5200p-48, | |
| 276 | 0x1.de7d5641c05bfp-1, -0x1.d700p-46, | |
| 277 | 0x1.dfc97337b9aecp-1, -0x1.6140p-46, | |
| 278 | 0x1.e11676b197d5ep-1, 0x1.b480p-47, | |
| 279 | 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43, | |
| 280 | 0x1.e3b333b16ee5cp-1, 0x1.c680p-47, | |
| 281 | 0x1.e502ee78b3fb4p-1, -0x1.9300p-47, | |
| 282 | 0x1.e653924676d68p-1, -0x1.5000p-49, | |
| 283 | 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47, | |
| 284 | 0x1.e8f7977cdb726p-1, -0x1.3700p-48, | |
| 285 | 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49, | |
| 286 | 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46, | |
| 287 | 0x1.ecf482d8e680dp-1, 0x1.5500p-48, | |
| 288 | 0x1.ee4aaa2188514p-1, 0x1.6400p-51, | |
| 289 | 0x1.efa1bee615a13p-1, -0x1.e800p-49, | |
| 290 | 0x1.f0f9c1cb64106p-1, -0x1.a880p-48, | |
| 291 | 0x1.f252b376bb963p-1, -0x1.c900p-45, | |
| 292 | 0x1.f3ac948dd7275p-1, 0x1.a000p-53, | |
| 293 | 0x1.f50765b6e4524p-1, -0x1.4f00p-48, | |
| 294 | 0x1.f6632798844fdp-1, 0x1.a800p-51, | |
| 295 | 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48, | |
| 296 | 0x1.f91d802243c82p-1, -0x1.4600p-50, | |
| 297 | 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47, | |
| 298 | 0x1.fbdba3692d511p-1, -0x1.0e00p-51, | |
| 299 | 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46, | |
| 300 | 0x1.fe9d96b2a23eep-1, 0x1.e430p-49, | |
| 301 | 0x1.0000000000000p+0, 0x0.0000p+0, | |
| 302 | 0x1.00b1afa5abcbep+0, -0x1.3400p-52, | |
| 303 | 0x1.0163da9fb3303p+0, -0x1.2170p-46, | |
| 304 | 0x1.02168143b0282p+0, 0x1.a400p-52, | |
| 305 | 0x1.02c9a3e77806cp+0, 0x1.f980p-49, | |
| 306 | 0x1.037d42e11bbcap+0, -0x1.7400p-51, | |
| 307 | 0x1.04315e86e7f89p+0, 0x1.8300p-50, | |
| 308 | 0x1.04e5f72f65467p+0, -0x1.a3f0p-46, | |
| 309 | 0x1.059b0d315855ap+0, -0x1.2840p-47, | |
| 310 | 0x1.0650a0e3c1f95p+0, 0x1.1600p-48, | |
| 311 | 0x1.0706b29ddf71ap+0, 0x1.5240p-46, | |
| 312 | 0x1.07bd42b72a82dp+0, -0x1.9a00p-49, | |
| 313 | 0x1.0874518759bd0p+0, 0x1.6400p-49, | |
| 314 | 0x1.092bdf66607c8p+0, -0x1.0780p-47, | |
| 315 | 0x1.09e3ecac6f383p+0, -0x1.8000p-54, | |
| 316 | 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48, | |
| 317 | 0x1.0b5586cf988fcp+0, -0x1.ac80p-48, | |
| 318 | 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50, | |
| 319 | 0x1.0cc922b724816p+0, 0x1.5200p-47, | |
| 320 | 0x1.0d83b23395dd8p+0, -0x1.ad00p-48, | |
| 321 | 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46, | |
| 322 | 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47, | |
| 323 | 0x1.0fb66affed2f0p+0, -0x1.d300p-47, | |
| 324 | 0x1.1073028d7234bp+0, 0x1.1500p-48, | |
| 325 | 0x1.11301d0125b5bp+0, 0x1.c000p-49, | |
| 326 | 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46, | |
| 327 | 0x1.12abdc06c31d5p+0, 0x1.8400p-49, | |
| 328 | 0x1.136a814f2047dp+0, -0x1.ed00p-47, | |
| 329 | 0x1.1429aaea92de9p+0, 0x1.8e00p-49, | |
| 330 | 0x1.14e95934f3138p+0, 0x1.b400p-49, | |
| 331 | 0x1.15a98c8a58e71p+0, 0x1.5300p-47, | |
| 332 | 0x1.166a45471c3dfp+0, 0x1.3380p-47, | |
| 333 | 0x1.172b83c7d5211p+0, 0x1.8d40p-45, | |
| 334 | 0x1.17ed48695bb9fp+0, -0x1.5d00p-47, | |
| 335 | 0x1.18af9388c8d93p+0, -0x1.c880p-46, | |
| 336 | 0x1.1972658375d66p+0, 0x1.1f00p-46, | |
| 337 | 0x1.1a35beb6fcba7p+0, 0x1.0480p-46, | |
| 338 | 0x1.1af99f81387e3p+0, -0x1.7390p-43, | |
| 339 | 0x1.1bbe084045d54p+0, 0x1.4e40p-45, | |
| 340 | 0x1.1c82f95281c43p+0, -0x1.a200p-47, | |
| 341 | 0x1.1d4873168b9b2p+0, 0x1.3800p-49, | |
| 342 | 0x1.1e0e75eb44031p+0, 0x1.ac00p-49, | |
| 343 | 0x1.1ed5022fcd938p+0, 0x1.1900p-47, | |
| 344 | 0x1.1f9c18438cdf7p+0, -0x1.b780p-46, | |
| 345 | 0x1.2063b88628d8fp+0, 0x1.d940p-45, | |
| 346 | 0x1.212be3578a81ep+0, 0x1.8000p-50, | |
| 347 | 0x1.21f49917ddd41p+0, 0x1.b340p-45, | |
| 348 | 0x1.22bdda2791323p+0, 0x1.9f80p-46, | |
| 349 | 0x1.2387a6e7561e7p+0, -0x1.9c80p-46, | |
| 350 | 0x1.2451ffb821427p+0, 0x1.2300p-47, | |
| 351 | 0x1.251ce4fb2a602p+0, -0x1.3480p-46, | |
| 352 | 0x1.25e85711eceb0p+0, 0x1.2700p-46, | |
| 353 | 0x1.26b4565e27d16p+0, 0x1.1d00p-46, | |
| 354 | 0x1.2780e341de00fp+0, 0x1.1ee0p-44, | |
| 355 | 0x1.284dfe1f5633ep+0, -0x1.4c00p-46, | |
| 356 | 0x1.291ba7591bb30p+0, -0x1.3d80p-46, | |
| 357 | 0x1.29e9df51fdf09p+0, 0x1.8b00p-47, | |
| 358 | 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45, | |
| 359 | 0x1.2b87fd0dada3ap+0, 0x1.a340p-45, | |
| 360 | 0x1.2c57e39771af9p+0, -0x1.0800p-46, | |
| 361 | 0x1.2d285a6e402d9p+0, -0x1.ed00p-47, | |
| 362 | 0x1.2df961f641579p+0, -0x1.4200p-48, | |
| 363 | 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45, | |
| 364 | 0x1.2f9d24abd8822p+0, -0x1.6300p-46, | |
| 365 | 0x1.306fe0a31b625p+0, -0x1.2360p-44, | |
| 366 | 0x1.31432edeea50bp+0, -0x1.0df8p-40, | |
| 367 | 0x1.32170fc4cd7b8p+0, -0x1.2480p-45, | |
| 368 | 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45, | |
| 369 | 0x1.33c08b2641766p+0, 0x1.ed00p-46, | |
| 370 | 0x1.3496266e3fa27p+0, -0x1.c000p-50, | |
| 371 | 0x1.356c55f929f0fp+0, -0x1.0d80p-44, | |
| 372 | 0x1.36431a2de88b9p+0, 0x1.2c80p-45, | |
| 373 | 0x1.371a7373aaa39p+0, 0x1.0600p-45, | |
| 374 | 0x1.37f26231e74fep+0, -0x1.6600p-46, | |
| 375 | 0x1.38cae6d05d838p+0, -0x1.ae00p-47, | |
| 376 | 0x1.39a401b713ec3p+0, -0x1.4720p-43, | |
| 377 | 0x1.3a7db34e5a020p+0, 0x1.8200p-47, | |
| 378 | 0x1.3b57fbfec6e95p+0, 0x1.e800p-44, | |
| 379 | 0x1.3c32dc313a8f2p+0, 0x1.f800p-49, | |
| 380 | 0x1.3d0e544ede122p+0, -0x1.7a00p-46, | |
| 381 | 0x1.3dea64c1234bbp+0, 0x1.6300p-45, | |
| 382 | 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43, | |
| 383 | 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44, | |
| 384 | 0x1.40822c367a0bbp+0, 0x1.5b80p-45, | |
| 385 | 0x1.4160a21f72e95p+0, 0x1.ec00p-46, | |
| 386 | 0x1.423fb27094646p+0, -0x1.3600p-46, | |
| 387 | 0x1.431f5d950a920p+0, 0x1.3980p-45, | |
| 388 | 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48, | |
| 389 | 0x1.44e0860618919p+0, -0x1.6c00p-48, | |
| 390 | 0x1.45c2042a7d201p+0, -0x1.bc00p-47, | |
| 391 | 0x1.46a41ed1d0016p+0, -0x1.2800p-46, | |
| 392 | 0x1.4786d668b3326p+0, 0x1.0e00p-44, | |
| 393 | 0x1.486a2b5c13c00p+0, -0x1.d400p-45, | |
| 394 | 0x1.494e1e192af04p+0, 0x1.c200p-47, | |
| 395 | 0x1.4a32af0d7d372p+0, -0x1.e500p-46, | |
| 396 | 0x1.4b17dea6db801p+0, 0x1.7800p-47, | |
| 397 | 0x1.4bfdad53629e1p+0, -0x1.3800p-46, | |
| 398 | 0x1.4ce41b817c132p+0, 0x1.0800p-47, | |
| 399 | 0x1.4dcb299fddddbp+0, 0x1.c700p-45, | |
| 400 | 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46, | |
| 401 | 0x1.4f9b2769d2d02p+0, 0x1.9200p-46, | |
| 402 | 0x1.508417f4531c1p+0, -0x1.8c00p-47, | |
| 403 | 0x1.516daa2cf662ap+0, -0x1.a000p-48, | |
| 404 | 0x1.5257de83f51eap+0, 0x1.a080p-43, | |
| 405 | 0x1.5342b569d4edap+0, -0x1.6d80p-45, | |
| 406 | 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44, | |
| 407 | 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43, | |
| 408 | 0x1.56070dde9116bp+0, 0x1.4b00p-45, | |
| 409 | 0x1.56f4736b529dep+0, 0x1.15a0p-43, | |
| 410 | 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45, | |
| 411 | 0x1.58d12d497c76fp+0, -0x1.3080p-45, | |
| 412 | 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43, | |
| 413 | 0x1.5ab07dd485427p+0, -0x1.4000p-51, | |
| 414 | 0x1.5ba11fba87af4p+0, 0x1.0080p-44, | |
| 415 | 0x1.5c9268a59460bp+0, -0x1.6c80p-45, | |
| 416 | 0x1.5d84590998e3fp+0, 0x1.69a0p-43, | |
| 417 | 0x1.5e76f15ad20e1p+0, -0x1.b400p-46, | |
| 418 | 0x1.5f6a320dcebcap+0, 0x1.7700p-46, | |
| 419 | 0x1.605e1b976dcb8p+0, 0x1.6f80p-45, | |
| 420 | 0x1.6152ae6cdf715p+0, 0x1.1000p-47, | |
| 421 | 0x1.6247eb03a5531p+0, -0x1.5d00p-46, | |
| 422 | 0x1.633dd1d1929b5p+0, -0x1.2d00p-46, | |
| 423 | 0x1.6434634ccc313p+0, -0x1.a800p-49, | |
| 424 | 0x1.652b9febc8efap+0, -0x1.8600p-45, | |
| 425 | 0x1.6623882553397p+0, 0x1.1fe0p-40, | |
| 426 | 0x1.671c1c708328ep+0, -0x1.7200p-44, | |
| 427 | 0x1.68155d44ca97ep+0, 0x1.6800p-49, | |
| 428 | 0x1.690f4b19e9471p+0, -0x1.9780p-45, | |
| 429 | }; | |
| 430 | ||
| 431 | test "exp2_32" { | |
| 432 | const epsilon = 0.000001; | |
| 433 | ||
| 434 | try expect(exp2f(0.0) == 1.0); | |
| 435 | try expect(math.approxEqAbs(f32, exp2f(0.2), 1.148698, epsilon)); | |
| 436 | try expect(math.approxEqAbs(f32, exp2f(0.8923), 1.856133, epsilon)); | |
| 437 | try expect(math.approxEqAbs(f32, exp2f(1.5), 2.828427, epsilon)); | |
| 438 | try expect(math.approxEqAbs(f32, exp2f(37.45), 187747237888, epsilon)); | |
| 439 | try expect(math.approxEqAbs(f32, exp2f(-1), 0.5, epsilon)); | |
| 440 | } | |
| 441 | ||
| 442 | test "exp2_64" { | |
| 443 | const epsilon = 0.000001; | |
| 444 | ||
| 445 | try expect(exp2(0.0) == 1.0); | |
| 446 | try expect(math.approxEqAbs(f64, exp2(0.2), 1.148698, epsilon)); | |
| 447 | try expect(math.approxEqAbs(f64, exp2(0.8923), 1.856133, epsilon)); | |
| 448 | try expect(math.approxEqAbs(f64, exp2(1.5), 2.828427, epsilon)); | |
| 449 | try expect(math.approxEqAbs(f64, exp2(-1), 0.5, epsilon)); | |
| 450 | try expect(math.approxEqAbs(f64, exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1, epsilon)); | |
| 451 | } | |
| 452 | ||
| 453 | test "exp2_32.special" { | |
| 454 | try expect(math.isPositiveInf(exp2f(math.inf(f32)))); | |
| 455 | try expect(math.isNan(exp2f(math.nan(f32)))); | |
| 456 | } | |
| 457 | ||
| 458 | test "exp2_64.special" { | |
| 459 | try expect(math.isPositiveInf(exp2(math.inf(f64)))); | |
| 460 | try expect(math.isNan(exp2(math.nan(f64)))); | |
| 461 | } |
lib/std/special/compiler_rt/fabs.zig created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn __fabsh(a: f16) callconv(.C) f16 { | |
| 4 | return generic_fabs(a); | |
| 5 | } | |
| 6 | ||
| 7 | pub fn fabsf(a: f32) callconv(.C) f32 { | |
| 8 | return generic_fabs(a); | |
| 9 | } | |
| 10 | ||
| 11 | pub fn fabs(a: f64) callconv(.C) f64 { | |
| 12 | return generic_fabs(a); | |
| 13 | } | |
| 14 | ||
| 15 | pub fn __fabsx(a: f80) callconv(.C) f80 { | |
| 16 | return generic_fabs(a); | |
| 17 | } | |
| 18 | ||
| 19 | pub fn fabsq(a: f128) callconv(.C) f128 { | |
| 20 | return generic_fabs(a); | |
| 21 | } | |
| 22 | ||
| 23 | inline fn generic_fabs(x: anytype) @TypeOf(x) { | |
| 24 | const T = @TypeOf(x); | |
| 25 | const TBits = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); | |
| 26 | const float_bits = @bitCast(TBits, x); | |
| 27 | const remove_sign = ~@as(TBits, 0) >> 1; | |
| 28 | return @bitCast(T, float_bits & remove_sign); | |
| 29 | } |
lib/std/special/compiler_rt/floor.zig created+198| ... | ... | @@ -0,0 +1,198 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | pub fn __floorh(x: f16) callconv(.C) f16 { | |
| 12 | var u = @bitCast(u16, x); | |
| 13 | const e = @intCast(i16, (u >> 10) & 31) - 15; | |
| 14 | var m: u16 = undefined; | |
| 15 | ||
| 16 | // TODO: Shouldn't need this explicit check. | |
| 17 | if (x == 0.0) { | |
| 18 | return x; | |
| 19 | } | |
| 20 | ||
| 21 | if (e >= 10) { | |
| 22 | return x; | |
| 23 | } | |
| 24 | ||
| 25 | if (e >= 0) { | |
| 26 | m = @as(u16, 1023) >> @intCast(u4, e); | |
| 27 | if (u & m == 0) { | |
| 28 | return x; | |
| 29 | } | |
| 30 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 31 | if (u >> 15 != 0) { | |
| 32 | u += m; | |
| 33 | } | |
| 34 | return @bitCast(f16, u & ~m); | |
| 35 | } else { | |
| 36 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 37 | if (u >> 15 == 0) { | |
| 38 | return 0.0; | |
| 39 | } else { | |
| 40 | return -1.0; | |
| 41 | } | |
| 42 | } | |
| 43 | } | |
| 44 | ||
| 45 | pub fn floorf(x: f32) callconv(.C) f32 { | |
| 46 | var u = @bitCast(u32, x); | |
| 47 | const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F; | |
| 48 | var m: u32 = undefined; | |
| 49 | ||
| 50 | // TODO: Shouldn't need this explicit check. | |
| 51 | if (x == 0.0) { | |
| 52 | return x; | |
| 53 | } | |
| 54 | ||
| 55 | if (e >= 23) { | |
| 56 | return x; | |
| 57 | } | |
| 58 | ||
| 59 | if (e >= 0) { | |
| 60 | m = @as(u32, 0x007FFFFF) >> @intCast(u5, e); | |
| 61 | if (u & m == 0) { | |
| 62 | return x; | |
| 63 | } | |
| 64 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 65 | if (u >> 31 != 0) { | |
| 66 | u += m; | |
| 67 | } | |
| 68 | return @bitCast(f32, u & ~m); | |
| 69 | } else { | |
| 70 | math.doNotOptimizeAway(x + 0x1.0p120); | |
| 71 | if (u >> 31 == 0) { | |
| 72 | return 0.0; | |
| 73 | } else { | |
| 74 | return -1.0; | |
| 75 | } | |
| 76 | } | |
| 77 | } | |
| 78 | ||
| 79 | pub fn floor(x: f64) callconv(.C) f64 { | |
| 80 | const f64_toint = 1.0 / math.floatEps(f64); | |
| 81 | ||
| 82 | const u = @bitCast(u64, x); | |
| 83 | const e = (u >> 52) & 0x7FF; | |
| 84 | var y: f64 = undefined; | |
| 85 | ||
| 86 | if (e >= 0x3FF + 52 or x == 0) { | |
| 87 | return x; | |
| 88 | } | |
| 89 | ||
| 90 | if (u >> 63 != 0) { | |
| 91 | y = x - f64_toint + f64_toint - x; | |
| 92 | } else { | |
| 93 | y = x + f64_toint - f64_toint - x; | |
| 94 | } | |
| 95 | ||
| 96 | if (e <= 0x3FF - 1) { | |
| 97 | math.doNotOptimizeAway(y); | |
| 98 | if (u >> 63 != 0) { | |
| 99 | return -1.0; | |
| 100 | } else { | |
| 101 | return 0.0; | |
| 102 | } | |
| 103 | } else if (y > 0) { | |
| 104 | return x + y - 1; | |
| 105 | } else { | |
| 106 | return x + y; | |
| 107 | } | |
| 108 | } | |
| 109 | ||
| 110 | pub fn __floorx(x: f80) callconv(.C) f80 { | |
| 111 | // TODO: more efficient implementation | |
| 112 | return @floatCast(f80, floorq(x)); | |
| 113 | } | |
| 114 | ||
| 115 | pub fn floorq(x: f128) callconv(.C) f128 { | |
| 116 | const f128_toint = 1.0 / math.floatEps(f128); | |
| 117 | ||
| 118 | const u = @bitCast(u128, x); | |
| 119 | const e = (u >> 112) & 0x7FFF; | |
| 120 | var y: f128 = undefined; | |
| 121 | ||
| 122 | if (e >= 0x3FFF + 112 or x == 0) return x; | |
| 123 | ||
| 124 | if (u >> 127 != 0) { | |
| 125 | y = x - f128_toint + f128_toint - x; | |
| 126 | } else { | |
| 127 | y = x + f128_toint - f128_toint - x; | |
| 128 | } | |
| 129 | ||
| 130 | if (e <= 0x3FFF - 1) { | |
| 131 | math.doNotOptimizeAway(y); | |
| 132 | if (u >> 127 != 0) { | |
| 133 | return -1.0; | |
| 134 | } else { | |
| 135 | return 0.0; | |
| 136 | } | |
| 137 | } else if (y > 0) { | |
| 138 | return x + y - 1; | |
| 139 | } else { | |
| 140 | return x + y; | |
| 141 | } | |
| 142 | } | |
| 143 | ||
| 144 | test "floor16" { | |
| 145 | try expect(__floorh(1.3) == 1.0); | |
| 146 | try expect(__floorh(-1.3) == -2.0); | |
| 147 | try expect(__floorh(0.2) == 0.0); | |
| 148 | } | |
| 149 | ||
| 150 | test "floor32" { | |
| 151 | try expect(floorf(1.3) == 1.0); | |
| 152 | try expect(floorf(-1.3) == -2.0); | |
| 153 | try expect(floorf(0.2) == 0.0); | |
| 154 | } | |
| 155 | ||
| 156 | test "floor64" { | |
| 157 | try expect(floor(1.3) == 1.0); | |
| 158 | try expect(floor(-1.3) == -2.0); | |
| 159 | try expect(floor(0.2) == 0.0); | |
| 160 | } | |
| 161 | ||
| 162 | test "floor128" { | |
| 163 | try expect(floorq(1.3) == 1.0); | |
| 164 | try expect(floorq(-1.3) == -2.0); | |
| 165 | try expect(floorq(0.2) == 0.0); | |
| 166 | } | |
| 167 | ||
| 168 | test "floor16.special" { | |
| 169 | try expect(__floorh(0.0) == 0.0); | |
| 170 | try expect(__floorh(-0.0) == -0.0); | |
| 171 | try expect(math.isPositiveInf(__floorh(math.inf(f16)))); | |
| 172 | try expect(math.isNegativeInf(__floorh(-math.inf(f16)))); | |
| 173 | try expect(math.isNan(__floorh(math.nan(f16)))); | |
| 174 | } | |
| 175 | ||
| 176 | test "floor32.special" { | |
| 177 | try expect(floorf(0.0) == 0.0); | |
| 178 | try expect(floorf(-0.0) == -0.0); | |
| 179 | try expect(math.isPositiveInf(floorf(math.inf(f32)))); | |
| 180 | try expect(math.isNegativeInf(floorf(-math.inf(f32)))); | |
| 181 | try expect(math.isNan(floorf(math.nan(f32)))); | |
| 182 | } | |
| 183 | ||
| 184 | test "floor64.special" { | |
| 185 | try expect(floor(0.0) == 0.0); | |
| 186 | try expect(floor(-0.0) == -0.0); | |
| 187 | try expect(math.isPositiveInf(floor(math.inf(f64)))); | |
| 188 | try expect(math.isNegativeInf(floor(-math.inf(f64)))); | |
| 189 | try expect(math.isNan(floor(math.nan(f64)))); | |
| 190 | } | |
| 191 | ||
| 192 | test "floor128.special" { | |
| 193 | try expect(floorq(0.0) == 0.0); | |
| 194 | try expect(floorq(-0.0) == -0.0); | |
| 195 | try expect(math.isPositiveInf(floorq(math.inf(f128)))); | |
| 196 | try expect(math.isNegativeInf(floorq(-math.inf(f128)))); | |
| 197 | try expect(math.isNan(floorq(math.nan(f128)))); | |
| 198 | } |
lib/std/special/compiler_rt/fma.zig created+327| ... | ... | @@ -0,0 +1,327 @@ |
| 1 | // Ported from musl, which is MIT licensed: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/fmal.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/fmaf.c | |
| 6 | // https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c | |
| 7 | ||
| 8 | const std = @import("std"); | |
| 9 | const math = std.math; | |
| 10 | const expect = std.testing.expect; | |
| 11 | ||
| 12 | pub fn __fmah(x: f16, y: f16, z: f16) callconv(.C) f16 { | |
| 13 | // TODO: more efficient implementation | |
| 14 | return @floatCast(f16, fmaf(x, y, z)); | |
| 15 | } | |
| 16 | ||
| 17 | pub fn fmaf(x: f32, y: f32, z: f32) callconv(.C) f32 { | |
| 18 | const xy = @as(f64, x) * y; | |
| 19 | const xy_z = xy + z; | |
| 20 | const u = @bitCast(u64, xy_z); | |
| 21 | const e = (u >> 52) & 0x7FF; | |
| 22 | ||
| 23 | if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or (xy_z - xy == z and xy_z - z == xy)) { | |
| 24 | return @floatCast(f32, xy_z); | |
| 25 | } else { | |
| 26 | // TODO: Handle inexact case with double-rounding | |
| 27 | return @floatCast(f32, xy_z); | |
| 28 | } | |
| 29 | } | |
| 30 | ||
| 31 | /// NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately. | |
| 32 | pub fn fma(x: f64, y: f64, z: f64) callconv(.C) f64 { | |
| 33 | if (!math.isFinite(x) or !math.isFinite(y)) { | |
| 34 | return x * y + z; | |
| 35 | } | |
| 36 | if (!math.isFinite(z)) { | |
| 37 | return z; | |
| 38 | } | |
| 39 | if (x == 0.0 or y == 0.0) { | |
| 40 | return x * y + z; | |
| 41 | } | |
| 42 | if (z == 0.0) { | |
| 43 | return x * y; | |
| 44 | } | |
| 45 | ||
| 46 | const x1 = math.frexp(x); | |
| 47 | var ex = x1.exponent; | |
| 48 | var xs = x1.significand; | |
| 49 | const x2 = math.frexp(y); | |
| 50 | var ey = x2.exponent; | |
| 51 | var ys = x2.significand; | |
| 52 | const x3 = math.frexp(z); | |
| 53 | var ez = x3.exponent; | |
| 54 | var zs = x3.significand; | |
| 55 | ||
| 56 | var spread = ex + ey - ez; | |
| 57 | if (spread <= 53 * 2) { | |
| 58 | zs = math.scalbn(zs, -spread); | |
| 59 | } else { | |
| 60 | zs = math.copysign(f64, math.floatMin(f64), zs); | |
| 61 | } | |
| 62 | ||
| 63 | const xy = dd_mul(xs, ys); | |
| 64 | const r = dd_add(xy.hi, zs); | |
| 65 | spread = ex + ey; | |
| 66 | ||
| 67 | if (r.hi == 0.0) { | |
| 68 | return xy.hi + zs + math.scalbn(xy.lo, spread); | |
| 69 | } | |
| 70 | ||
| 71 | const adj = add_adjusted(r.lo, xy.lo); | |
| 72 | if (spread + math.ilogb(r.hi) > -1023) { | |
| 73 | return math.scalbn(r.hi + adj, spread); | |
| 74 | } else { | |
| 75 | return add_and_denorm(r.hi, adj, spread); | |
| 76 | } | |
| 77 | } | |
| 78 | ||
| 79 | pub fn __fmax(a: f80, b: f80, c: f80) callconv(.C) f80 { | |
| 80 | // TODO: more efficient implementation | |
| 81 | return @floatCast(f80, fmaq(a, b, c)); | |
| 82 | } | |
| 83 | ||
| 84 | /// Fused multiply-add: Compute x * y + z with a single rounding error. | |
| 85 | /// | |
| 86 | /// We use scaling to avoid overflow/underflow, along with the | |
| 87 | /// canonical precision-doubling technique adapted from: | |
| 88 | /// | |
| 89 | /// Dekker, T. A Floating-Point Technique for Extending the | |
| 90 | /// Available Precision. Numer. Math. 18, 224-242 (1971). | |
| 91 | pub fn fmaq(x: f128, y: f128, z: f128) callconv(.C) f128 { | |
| 92 | if (!math.isFinite(x) or !math.isFinite(y)) { | |
| 93 | return x * y + z; | |
| 94 | } | |
| 95 | if (!math.isFinite(z)) { | |
| 96 | return z; | |
| 97 | } | |
| 98 | if (x == 0.0 or y == 0.0) { | |
| 99 | return x * y + z; | |
| 100 | } | |
| 101 | if (z == 0.0) { | |
| 102 | return x * y; | |
| 103 | } | |
| 104 | ||
| 105 | const x1 = math.frexp(x); | |
| 106 | var ex = x1.exponent; | |
| 107 | var xs = x1.significand; | |
| 108 | const x2 = math.frexp(y); | |
| 109 | var ey = x2.exponent; | |
| 110 | var ys = x2.significand; | |
| 111 | const x3 = math.frexp(z); | |
| 112 | var ez = x3.exponent; | |
| 113 | var zs = x3.significand; | |
| 114 | ||
| 115 | var spread = ex + ey - ez; | |
| 116 | if (spread <= 113 * 2) { | |
| 117 | zs = math.scalbn(zs, -spread); | |
| 118 | } else { | |
| 119 | zs = math.copysign(f128, math.floatMin(f128), zs); | |
| 120 | } | |
| 121 | ||
| 122 | const xy = dd_mul128(xs, ys); | |
| 123 | const r = dd_add128(xy.hi, zs); | |
| 124 | spread = ex + ey; | |
| 125 | ||
| 126 | if (r.hi == 0.0) { | |
| 127 | return xy.hi + zs + math.scalbn(xy.lo, spread); | |
| 128 | } | |
| 129 | ||
| 130 | const adj = add_adjusted128(r.lo, xy.lo); | |
| 131 | if (spread + math.ilogb(r.hi) > -16383) { | |
| 132 | return math.scalbn(r.hi + adj, spread); | |
| 133 | } else { | |
| 134 | return add_and_denorm128(r.hi, adj, spread); | |
| 135 | } | |
| 136 | } | |
| 137 | ||
| 138 | const dd = struct { | |
| 139 | hi: f64, | |
| 140 | lo: f64, | |
| 141 | }; | |
| 142 | ||
| 143 | fn dd_add(a: f64, b: f64) dd { | |
| 144 | var ret: dd = undefined; | |
| 145 | ret.hi = a + b; | |
| 146 | const s = ret.hi - a; | |
| 147 | ret.lo = (a - (ret.hi - s)) + (b - s); | |
| 148 | return ret; | |
| 149 | } | |
| 150 | ||
| 151 | fn dd_mul(a: f64, b: f64) dd { | |
| 152 | var ret: dd = undefined; | |
| 153 | const split: f64 = 0x1.0p27 + 1.0; | |
| 154 | ||
| 155 | var p = a * split; | |
| 156 | var ha = a - p; | |
| 157 | ha += p; | |
| 158 | var la = a - ha; | |
| 159 | ||
| 160 | p = b * split; | |
| 161 | var hb = b - p; | |
| 162 | hb += p; | |
| 163 | var lb = b - hb; | |
| 164 | ||
| 165 | p = ha * hb; | |
| 166 | var q = ha * lb + la * hb; | |
| 167 | ||
| 168 | ret.hi = p + q; | |
| 169 | ret.lo = p - ret.hi + q + la * lb; | |
| 170 | return ret; | |
| 171 | } | |
| 172 | ||
| 173 | fn add_adjusted(a: f64, b: f64) f64 { | |
| 174 | var sum = dd_add(a, b); | |
| 175 | if (sum.lo != 0) { | |
| 176 | var uhii = @bitCast(u64, sum.hi); | |
| 177 | if (uhii & 1 == 0) { | |
| 178 | // hibits += copysign(1.0, sum.hi, sum.lo) | |
| 179 | const uloi = @bitCast(u64, sum.lo); | |
| 180 | uhii += 1 - ((uhii ^ uloi) >> 62); | |
| 181 | sum.hi = @bitCast(f64, uhii); | |
| 182 | } | |
| 183 | } | |
| 184 | return sum.hi; | |
| 185 | } | |
| 186 | ||
| 187 | fn add_and_denorm(a: f64, b: f64, scale: i32) f64 { | |
| 188 | var sum = dd_add(a, b); | |
| 189 | if (sum.lo != 0) { | |
| 190 | var uhii = @bitCast(u64, sum.hi); | |
| 191 | const bits_lost = -@intCast(i32, (uhii >> 52) & 0x7FF) - scale + 1; | |
| 192 | if ((bits_lost != 1) == (uhii & 1 != 0)) { | |
| 193 | const uloi = @bitCast(u64, sum.lo); | |
| 194 | uhii += 1 - (((uhii ^ uloi) >> 62) & 2); | |
| 195 | sum.hi = @bitCast(f64, uhii); | |
| 196 | } | |
| 197 | } | |
| 198 | return math.scalbn(sum.hi, scale); | |
| 199 | } | |
| 200 | ||
| 201 | /// A struct that represents a floating-point number with twice the precision | |
| 202 | /// of f128. We maintain the invariant that "hi" stores the high-order | |
| 203 | /// bits of the result. | |
| 204 | const dd128 = struct { | |
| 205 | hi: f128, | |
| 206 | lo: f128, | |
| 207 | }; | |
| 208 | ||
| 209 | /// Compute a+b exactly, returning the exact result in a struct dd. We assume | |
| 210 | /// that both a and b are finite, but make no assumptions about their relative | |
| 211 | /// magnitudes. | |
| 212 | fn dd_add128(a: f128, b: f128) dd128 { | |
| 213 | var ret: dd128 = undefined; | |
| 214 | ret.hi = a + b; | |
| 215 | const s = ret.hi - a; | |
| 216 | ret.lo = (a - (ret.hi - s)) + (b - s); | |
| 217 | return ret; | |
| 218 | } | |
| 219 | ||
| 220 | /// Compute a+b, with a small tweak: The least significant bit of the | |
| 221 | /// result is adjusted into a sticky bit summarizing all the bits that | |
| 222 | /// were lost to rounding. This adjustment negates the effects of double | |
| 223 | /// rounding when the result is added to another number with a higher | |
| 224 | /// exponent. For an explanation of round and sticky bits, see any reference | |
| 225 | /// on FPU design, e.g., | |
| 226 | /// | |
| 227 | /// J. Coonen. An Implementation Guide to a Proposed Standard for | |
| 228 | /// Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. | |
| 229 | fn add_adjusted128(a: f128, b: f128) f128 { | |
| 230 | var sum = dd_add128(a, b); | |
| 231 | if (sum.lo != 0) { | |
| 232 | var uhii = @bitCast(u128, sum.hi); | |
| 233 | if (uhii & 1 == 0) { | |
| 234 | // hibits += copysign(1.0, sum.hi, sum.lo) | |
| 235 | const uloi = @bitCast(u128, sum.lo); | |
| 236 | uhii += 1 - ((uhii ^ uloi) >> 126); | |
| 237 | sum.hi = @bitCast(f128, uhii); | |
| 238 | } | |
| 239 | } | |
| 240 | return sum.hi; | |
| 241 | } | |
| 242 | ||
| 243 | /// Compute ldexp(a+b, scale) with a single rounding error. It is assumed | |
| 244 | /// that the result will be subnormal, and care is taken to ensure that | |
| 245 | /// double rounding does not occur. | |
| 246 | fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 { | |
| 247 | var sum = dd_add128(a, b); | |
| 248 | // If we are losing at least two bits of accuracy to denormalization, | |
| 249 | // then the first lost bit becomes a round bit, and we adjust the | |
| 250 | // lowest bit of sum.hi to make it a sticky bit summarizing all the | |
| 251 | // bits in sum.lo. With the sticky bit adjusted, the hardware will | |
| 252 | // break any ties in the correct direction. | |
| 253 | // | |
| 254 | // If we are losing only one bit to denormalization, however, we must | |
| 255 | // break the ties manually. | |
| 256 | if (sum.lo != 0) { | |
| 257 | var uhii = @bitCast(u128, sum.hi); | |
| 258 | const bits_lost = -@intCast(i32, (uhii >> 112) & 0x7FFF) - scale + 1; | |
| 259 | if ((bits_lost != 1) == (uhii & 1 != 0)) { | |
| 260 | const uloi = @bitCast(u128, sum.lo); | |
| 261 | uhii += 1 - (((uhii ^ uloi) >> 126) & 2); | |
| 262 | sum.hi = @bitCast(f128, uhii); | |
| 263 | } | |
| 264 | } | |
| 265 | return math.scalbn(sum.hi, scale); | |
| 266 | } | |
| 267 | ||
| 268 | /// Compute a*b exactly, returning the exact result in a struct dd. We assume | |
| 269 | /// that both a and b are normalized, so no underflow or overflow will occur. | |
| 270 | /// The current rounding mode must be round-to-nearest. | |
| 271 | fn dd_mul128(a: f128, b: f128) dd128 { | |
| 272 | var ret: dd128 = undefined; | |
| 273 | const split: f128 = 0x1.0p57 + 1.0; | |
| 274 | ||
| 275 | var p = a * split; | |
| 276 | var ha = a - p; | |
| 277 | ha += p; | |
| 278 | var la = a - ha; | |
| 279 | ||
| 280 | p = b * split; | |
| 281 | var hb = b - p; | |
| 282 | hb += p; | |
| 283 | var lb = b - hb; | |
| 284 | ||
| 285 | p = ha * hb; | |
| 286 | var q = ha * lb + la * hb; | |
| 287 | ||
| 288 | ret.hi = p + q; | |
| 289 | ret.lo = p - ret.hi + q + la * lb; | |
| 290 | return ret; | |
| 291 | } | |
| 292 | ||
| 293 | test "32" { | |
| 294 | const epsilon = 0.000001; | |
| 295 | ||
| 296 | try expect(math.approxEqAbs(f32, fmaf(0.0, 5.0, 9.124), 9.124, epsilon)); | |
| 297 | try expect(math.approxEqAbs(f32, fmaf(0.2, 5.0, 9.124), 10.124, epsilon)); | |
| 298 | try expect(math.approxEqAbs(f32, fmaf(0.8923, 5.0, 9.124), 13.5855, epsilon)); | |
| 299 | try expect(math.approxEqAbs(f32, fmaf(1.5, 5.0, 9.124), 16.624, epsilon)); | |
| 300 | try expect(math.approxEqAbs(f32, fmaf(37.45, 5.0, 9.124), 196.374004, epsilon)); | |
| 301 | try expect(math.approxEqAbs(f32, fmaf(89.123, 5.0, 9.124), 454.739005, epsilon)); | |
| 302 | try expect(math.approxEqAbs(f32, fmaf(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); | |
| 303 | } | |
| 304 | ||
| 305 | test "64" { | |
| 306 | const epsilon = 0.000001; | |
| 307 | ||
| 308 | try expect(math.approxEqAbs(f64, fma(0.0, 5.0, 9.124), 9.124, epsilon)); | |
| 309 | try expect(math.approxEqAbs(f64, fma(0.2, 5.0, 9.124), 10.124, epsilon)); | |
| 310 | try expect(math.approxEqAbs(f64, fma(0.8923, 5.0, 9.124), 13.5855, epsilon)); | |
| 311 | try expect(math.approxEqAbs(f64, fma(1.5, 5.0, 9.124), 16.624, epsilon)); | |
| 312 | try expect(math.approxEqAbs(f64, fma(37.45, 5.0, 9.124), 196.374, epsilon)); | |
| 313 | try expect(math.approxEqAbs(f64, fma(89.123, 5.0, 9.124), 454.739, epsilon)); | |
| 314 | try expect(math.approxEqAbs(f64, fma(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); | |
| 315 | } | |
| 316 | ||
| 317 | test "128" { | |
| 318 | const epsilon = 0.000001; | |
| 319 | ||
| 320 | try expect(math.approxEqAbs(f128, fmaq(0.0, 5.0, 9.124), 9.124, epsilon)); | |
| 321 | try expect(math.approxEqAbs(f128, fmaq(0.2, 5.0, 9.124), 10.124, epsilon)); | |
| 322 | try expect(math.approxEqAbs(f128, fmaq(0.8923, 5.0, 9.124), 13.5855, epsilon)); | |
| 323 | try expect(math.approxEqAbs(f128, fmaq(1.5, 5.0, 9.124), 16.624, epsilon)); | |
| 324 | try expect(math.approxEqAbs(f128, fmaq(37.45, 5.0, 9.124), 196.374, epsilon)); | |
| 325 | try expect(math.approxEqAbs(f128, fmaq(89.123, 5.0, 9.124), 454.739, epsilon)); | |
| 326 | try expect(math.approxEqAbs(f128, fmaq(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); | |
| 327 | } |
lib/std/special/compiler_rt/fmax.zig created+43| ... | ... | @@ -0,0 +1,43 @@ |
| 1 | const std = @import("std"); | |
| 2 | const math = std.math; | |
| 3 | ||
| 4 | pub fn __fmaxh(x: f16, y: f16) callconv(.C) f16 { | |
| 5 | return generic_fmax(f16, x, y); | |
| 6 | } | |
| 7 | ||
| 8 | pub fn fmaxf(x: f32, y: f32) callconv(.C) f32 { | |
| 9 | return generic_fmax(f32, x, y); | |
| 10 | } | |
| 11 | ||
| 12 | pub fn fmax(x: f64, y: f64) callconv(.C) f64 { | |
| 13 | return generic_fmax(f64, x, y); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn __fmaxx(x: f80, y: f80) callconv(.C) f80 { | |
| 17 | return generic_fmax(f80, x, y); | |
| 18 | } | |
| 19 | ||
| 20 | pub fn fmaxq(x: f128, y: f128) callconv(.C) f128 { | |
| 21 | return generic_fmax(f128, x, y); | |
| 22 | } | |
| 23 | ||
| 24 | inline fn generic_fmax(comptime T: type, x: T, y: T) T { | |
| 25 | if (math.isNan(x)) | |
| 26 | return y; | |
| 27 | if (math.isNan(y)) | |
| 28 | return x; | |
| 29 | return if (x < y) y else x; | |
| 30 | } | |
| 31 | ||
| 32 | test "generic_fmax" { | |
| 33 | inline for ([_]type{ f32, f64, c_longdouble, f80, f128 }) |T| { | |
| 34 | const nan_val = math.nan(T); | |
| 35 | ||
| 36 | try std.testing.expect(math.isNan(generic_fmax(T, nan_val, nan_val))); | |
| 37 | try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, nan_val, 1.0)); | |
| 38 | try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, nan_val)); | |
| 39 | ||
| 40 | try std.testing.expectEqual(@as(T, 10.0), generic_fmax(T, 1.0, 10.0)); | |
| 41 | try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, -1.0)); | |
| 42 | } | |
| 43 | } |
lib/std/special/compiler_rt/fmin.zig created+43| ... | ... | @@ -0,0 +1,43 @@ |
| 1 | const std = @import("std"); | |
| 2 | const math = std.math; | |
| 3 | ||
| 4 | pub fn __fminh(x: f16, y: f16) callconv(.C) f16 { | |
| 5 | return generic_fmin(f16, x, y); | |
| 6 | } | |
| 7 | ||
| 8 | pub fn fminf(x: f32, y: f32) callconv(.C) f32 { | |
| 9 | return generic_fmin(f32, x, y); | |
| 10 | } | |
| 11 | ||
| 12 | pub fn fmin(x: f64, y: f64) callconv(.C) f64 { | |
| 13 | return generic_fmin(f64, x, y); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn __fminx(x: f80, y: f80) callconv(.C) f80 { | |
| 17 | return generic_fmin(f80, x, y); | |
| 18 | } | |
| 19 | ||
| 20 | pub fn fminq(x: f128, y: f128) callconv(.C) f128 { | |
| 21 | return generic_fmin(f128, x, y); | |
| 22 | } | |
| 23 | ||
| 24 | inline fn generic_fmin(comptime T: type, x: T, y: T) T { | |
| 25 | if (math.isNan(x)) | |
| 26 | return y; | |
| 27 | if (math.isNan(y)) | |
| 28 | return x; | |
| 29 | return if (x < y) x else y; | |
| 30 | } | |
| 31 | ||
| 32 | test "generic_fmin" { | |
| 33 | inline for ([_]type{ f32, f64, c_longdouble, f80, f128 }) |T| { | |
| 34 | const nan_val = math.nan(T); | |
| 35 | ||
| 36 | try std.testing.expect(math.isNan(generic_fmin(T, nan_val, nan_val))); | |
| 37 | try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, nan_val, 1.0)); | |
| 38 | try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, nan_val)); | |
| 39 | ||
| 40 | try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, 10.0)); | |
| 41 | try std.testing.expectEqual(@as(T, -1.0), generic_fmin(T, 1.0, -1.0)); | |
| 42 | } | |
| 43 | } |
lib/std/special/compiler_rt/fmod.zig created+351| ... | ... | @@ -0,0 +1,351 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const math = std.math; | |
| 4 | const assert = std.debug.assert; | |
| 5 | const normalize = @import("divdf3.zig").normalize; | |
| 6 | ||
| 7 | pub fn __fmodh(x: f16, y: f16) callconv(.C) f16 { | |
| 8 | // TODO: more efficient implementation | |
| 9 | return @floatCast(f16, fmodf(x, y)); | |
| 10 | } | |
| 11 | ||
| 12 | pub fn fmodf(x: f32, y: f32) callconv(.C) f32 { | |
| 13 | return generic_fmod(f32, x, y); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn fmod(x: f64, y: f64) callconv(.C) f64 { | |
| 17 | return generic_fmod(f64, x, y); | |
| 18 | } | |
| 19 | ||
| 20 | /// fmodx - floating modulo large, returns the remainder of division for f80 types | |
| 21 | /// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits | |
| 22 | pub fn __fmodx(a: f80, b: f80) callconv(.C) f80 { | |
| 23 | @setRuntimeSafety(builtin.is_test); | |
| 24 | ||
| 25 | const T = f80; | |
| 26 | const Z = std.meta.Int(.unsigned, @bitSizeOf(T)); | |
| 27 | ||
| 28 | const significandBits = math.floatMantissaBits(T); | |
| 29 | const fractionalBits = math.floatFractionalBits(T); | |
| 30 | const exponentBits = math.floatExponentBits(T); | |
| 31 | ||
| 32 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); | |
| 33 | const maxExponent = ((1 << exponentBits) - 1); | |
| 34 | ||
| 35 | var aRep = @bitCast(Z, a); | |
| 36 | var bRep = @bitCast(Z, b); | |
| 37 | ||
| 38 | const signA = aRep & signBit; | |
| 39 | var expA = @intCast(i32, (@bitCast(Z, a) >> significandBits) & maxExponent); | |
| 40 | var expB = @intCast(i32, (@bitCast(Z, b) >> significandBits) & maxExponent); | |
| 41 | ||
| 42 | // There are 3 cases where the answer is undefined, check for: | |
| 43 | // - fmodx(val, 0) | |
| 44 | // - fmodx(val, NaN) | |
| 45 | // - fmodx(inf, val) | |
| 46 | // The sign on checked values does not matter. | |
| 47 | // Doing (a * b) / (a * b) procudes undefined results | |
| 48 | // because the three cases always produce undefined calculations: | |
| 49 | // - 0 / 0 | |
| 50 | // - val * NaN | |
| 51 | // - inf / inf | |
| 52 | if (b == 0 or math.isNan(b) or expA == maxExponent) { | |
| 53 | return (a * b) / (a * b); | |
| 54 | } | |
| 55 | ||
| 56 | // Remove the sign from both | |
| 57 | aRep &= ~signBit; | |
| 58 | bRep &= ~signBit; | |
| 59 | if (aRep <= bRep) { | |
| 60 | if (aRep == bRep) { | |
| 61 | return 0 * a; | |
| 62 | } | |
| 63 | return a; | |
| 64 | } | |
| 65 | ||
| 66 | if (expA == 0) expA = normalize(f80, &aRep); | |
| 67 | if (expB == 0) expB = normalize(f80, &bRep); | |
| 68 | ||
| 69 | var highA: u64 = 0; | |
| 70 | var highB: u64 = 0; | |
| 71 | var lowA: u64 = @truncate(u64, aRep); | |
| 72 | var lowB: u64 = @truncate(u64, bRep); | |
| 73 | ||
| 74 | while (expA > expB) : (expA -= 1) { | |
| 75 | var high = highA -% highB; | |
| 76 | var low = lowA -% lowB; | |
| 77 | if (lowA < lowB) { | |
| 78 | high -%= 1; | |
| 79 | } | |
| 80 | if (high >> 63 == 0) { | |
| 81 | if ((high | low) == 0) { | |
| 82 | return 0 * a; | |
| 83 | } | |
| 84 | highA = 2 *% high + (low >> 63); | |
| 85 | lowA = 2 *% low; | |
| 86 | } else { | |
| 87 | highA = 2 *% highA + (lowA >> 63); | |
| 88 | lowA = 2 *% lowA; | |
| 89 | } | |
| 90 | } | |
| 91 | ||
| 92 | var high = highA -% highB; | |
| 93 | var low = lowA -% lowB; | |
| 94 | if (lowA < lowB) { | |
| 95 | high -%= 1; | |
| 96 | } | |
| 97 | if (high >> 63 == 0) { | |
| 98 | if ((high | low) == 0) { | |
| 99 | return 0 * a; | |
| 100 | } | |
| 101 | highA = high; | |
| 102 | lowA = low; | |
| 103 | } | |
| 104 | ||
| 105 | while ((lowA >> fractionalBits) == 0) { | |
| 106 | lowA = 2 *% lowA; | |
| 107 | expA = expA - 1; | |
| 108 | } | |
| 109 | ||
| 110 | // Combine the exponent with the sign and significand, normalize if happened to be denormalized | |
| 111 | if (expA < -fractionalBits) { | |
| 112 | return @bitCast(T, signA); | |
| 113 | } else if (expA <= 0) { | |
| 114 | return @bitCast(T, (lowA >> @intCast(math.Log2Int(u64), 1 - expA)) | signA); | |
| 115 | } else { | |
| 116 | return @bitCast(T, lowA | (@as(Z, @intCast(u16, expA)) << significandBits) | signA); | |
| 117 | } | |
| 118 | } | |
| 119 | ||
| 120 | /// fmodq - floating modulo large, returns the remainder of division for f128 types | |
| 121 | /// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits | |
| 122 | pub fn fmodq(a: f128, b: f128) callconv(.C) f128 { | |
| 123 | @setRuntimeSafety(builtin.is_test); | |
| 124 | var amod = a; | |
| 125 | var bmod = b; | |
| 126 | const aPtr_u64 = @ptrCast([*]u64, &amod); | |
| 127 | const bPtr_u64 = @ptrCast([*]u64, &bmod); | |
| 128 | const aPtr_u16 = @ptrCast([*]u16, &amod); | |
| 129 | const bPtr_u16 = @ptrCast([*]u16, &bmod); | |
| 130 | ||
| 131 | const exp_and_sign_index = comptime switch (builtin.target.cpu.arch.endian()) { | |
| 132 | .Little => 7, | |
| 133 | .Big => 0, | |
| 134 | }; | |
| 135 | const low_index = comptime switch (builtin.target.cpu.arch.endian()) { | |
| 136 | .Little => 0, | |
| 137 | .Big => 1, | |
| 138 | }; | |
| 139 | const high_index = comptime switch (builtin.target.cpu.arch.endian()) { | |
| 140 | .Little => 1, | |
| 141 | .Big => 0, | |
| 142 | }; | |
| 143 | ||
| 144 | const signA = aPtr_u16[exp_and_sign_index] & 0x8000; | |
| 145 | var expA = @intCast(i32, (aPtr_u16[exp_and_sign_index] & 0x7fff)); | |
| 146 | var expB = @intCast(i32, (bPtr_u16[exp_and_sign_index] & 0x7fff)); | |
| 147 | ||
| 148 | // There are 3 cases where the answer is undefined, check for: | |
| 149 | // - fmodq(val, 0) | |
| 150 | // - fmodq(val, NaN) | |
| 151 | // - fmodq(inf, val) | |
| 152 | // The sign on checked values does not matter. | |
| 153 | // Doing (a * b) / (a * b) procudes undefined results | |
| 154 | // because the three cases always produce undefined calculations: | |
| 155 | // - 0 / 0 | |
| 156 | // - val * NaN | |
| 157 | // - inf / inf | |
| 158 | if (b == 0 or std.math.isNan(b) or expA == 0x7fff) { | |
| 159 | return (a * b) / (a * b); | |
| 160 | } | |
| 161 | ||
| 162 | // Remove the sign from both | |
| 163 | aPtr_u16[exp_and_sign_index] = @bitCast(u16, @intCast(i16, expA)); | |
| 164 | bPtr_u16[exp_and_sign_index] = @bitCast(u16, @intCast(i16, expB)); | |
| 165 | if (amod <= bmod) { | |
| 166 | if (amod == bmod) { | |
| 167 | return 0 * a; | |
| 168 | } | |
| 169 | return a; | |
| 170 | } | |
| 171 | ||
| 172 | if (expA == 0) { | |
| 173 | amod *= 0x1p120; | |
| 174 | expA = @as(i32, aPtr_u16[exp_and_sign_index]) - 120; | |
| 175 | } | |
| 176 | ||
| 177 | if (expB == 0) { | |
| 178 | bmod *= 0x1p120; | |
| 179 | expB = @as(i32, bPtr_u16[exp_and_sign_index]) - 120; | |
| 180 | } | |
| 181 | ||
| 182 | // OR in extra non-stored mantissa digit | |
| 183 | var highA: u64 = (aPtr_u64[high_index] & (std.math.maxInt(u64) >> 16)) | 1 << 48; | |
| 184 | var highB: u64 = (bPtr_u64[high_index] & (std.math.maxInt(u64) >> 16)) | 1 << 48; | |
| 185 | var lowA: u64 = aPtr_u64[low_index]; | |
| 186 | var lowB: u64 = bPtr_u64[low_index]; | |
| 187 | ||
| 188 | while (expA > expB) : (expA -= 1) { | |
| 189 | var high = highA -% highB; | |
| 190 | var low = lowA -% lowB; | |
| 191 | if (lowA < lowB) { | |
| 192 | high -%= 1; | |
| 193 | } | |
| 194 | if (high >> 63 == 0) { | |
| 195 | if ((high | low) == 0) { | |
| 196 | return 0 * a; | |
| 197 | } | |
| 198 | highA = 2 *% high + (low >> 63); | |
| 199 | lowA = 2 *% low; | |
| 200 | } else { | |
| 201 | highA = 2 *% highA + (lowA >> 63); | |
| 202 | lowA = 2 *% lowA; | |
| 203 | } | |
| 204 | } | |
| 205 | ||
| 206 | var high = highA -% highB; | |
| 207 | var low = lowA -% lowB; | |
| 208 | if (lowA < lowB) { | |
| 209 | high -= 1; | |
| 210 | } | |
| 211 | if (high >> 63 == 0) { | |
| 212 | if ((high | low) == 0) { | |
| 213 | return 0 * a; | |
| 214 | } | |
| 215 | highA = high; | |
| 216 | lowA = low; | |
| 217 | } | |
| 218 | ||
| 219 | while (highA >> 48 == 0) { | |
| 220 | highA = 2 *% highA + (lowA >> 63); | |
| 221 | lowA = 2 *% lowA; | |
| 222 | expA = expA - 1; | |
| 223 | } | |
| 224 | ||
| 225 | // Overwrite the current amod with the values in highA and lowA | |
| 226 | aPtr_u64[high_index] = highA; | |
| 227 | aPtr_u64[low_index] = lowA; | |
| 228 | ||
| 229 | // Combine the exponent with the sign, normalize if happend to be denormalized | |
| 230 | if (expA <= 0) { | |
| 231 | aPtr_u16[exp_and_sign_index] = @truncate(u16, @bitCast(u32, (expA +% 120))) | signA; | |
| 232 | amod *= 0x1p-120; | |
| 233 | } else { | |
| 234 | aPtr_u16[exp_and_sign_index] = @truncate(u16, @bitCast(u32, expA)) | signA; | |
| 235 | } | |
| 236 | ||
| 237 | return amod; | |
| 238 | } | |
| 239 | ||
| 240 | inline fn generic_fmod(comptime T: type, x: T, y: T) T { | |
| 241 | @setRuntimeSafety(false); | |
| 242 | ||
| 243 | const bits = @typeInfo(T).Float.bits; | |
| 244 | const uint = std.meta.Int(.unsigned, bits); | |
| 245 | const log2uint = math.Log2Int(uint); | |
| 246 | comptime assert(T == f32 or T == f64); | |
| 247 | const digits = if (T == f32) 23 else 52; | |
| 248 | const exp_bits = if (T == f32) 9 else 12; | |
| 249 | const bits_minus_1 = bits - 1; | |
| 250 | const mask = if (T == f32) 0xff else 0x7ff; | |
| 251 | var ux = @bitCast(uint, x); | |
| 252 | var uy = @bitCast(uint, y); | |
| 253 | var ex = @intCast(i32, (ux >> digits) & mask); | |
| 254 | var ey = @intCast(i32, (uy >> digits) & mask); | |
| 255 | const sx = if (T == f32) @intCast(u32, ux & 0x80000000) else @intCast(i32, ux >> bits_minus_1); | |
| 256 | var i: uint = undefined; | |
| 257 | ||
| 258 | if (uy << 1 == 0 or math.isNan(@bitCast(T, uy)) or ex == mask) | |
| 259 | return (x * y) / (x * y); | |
| 260 | ||
| 261 | if (ux << 1 <= uy << 1) { | |
| 262 | if (ux << 1 == uy << 1) | |
| 263 | return 0 * x; | |
| 264 | return x; | |
| 265 | } | |
| 266 | ||
| 267 | // normalize x and y | |
| 268 | if (ex == 0) { | |
| 269 | i = ux << exp_bits; | |
| 270 | while (i >> bits_minus_1 == 0) : ({ | |
| 271 | ex -= 1; | |
| 272 | i <<= 1; | |
| 273 | }) {} | |
| 274 | ux <<= @intCast(log2uint, @bitCast(u32, -ex + 1)); | |
| 275 | } else { | |
| 276 | ux &= math.maxInt(uint) >> exp_bits; | |
| 277 | ux |= 1 << digits; | |
| 278 | } | |
| 279 | if (ey == 0) { | |
| 280 | i = uy << exp_bits; | |
| 281 | while (i >> bits_minus_1 == 0) : ({ | |
| 282 | ey -= 1; | |
| 283 | i <<= 1; | |
| 284 | }) {} | |
| 285 | uy <<= @intCast(log2uint, @bitCast(u32, -ey + 1)); | |
| 286 | } else { | |
| 287 | uy &= math.maxInt(uint) >> exp_bits; | |
| 288 | uy |= 1 << digits; | |
| 289 | } | |
| 290 | ||
| 291 | // x mod y | |
| 292 | while (ex > ey) : (ex -= 1) { | |
| 293 | i = ux -% uy; | |
| 294 | if (i >> bits_minus_1 == 0) { | |
| 295 | if (i == 0) | |
| 296 | return 0 * x; | |
| 297 | ux = i; | |
| 298 | } | |
| 299 | ux <<= 1; | |
| 300 | } | |
| 301 | i = ux -% uy; | |
| 302 | if (i >> bits_minus_1 == 0) { | |
| 303 | if (i == 0) | |
| 304 | return 0 * x; | |
| 305 | ux = i; | |
| 306 | } | |
| 307 | while (ux >> digits == 0) : ({ | |
| 308 | ux <<= 1; | |
| 309 | ex -= 1; | |
| 310 | }) {} | |
| 311 | ||
| 312 | // scale result up | |
| 313 | if (ex > 0) { | |
| 314 | ux -%= 1 << digits; | |
| 315 | ux |= @as(uint, @bitCast(u32, ex)) << digits; | |
| 316 | } else { | |
| 317 | ux >>= @intCast(log2uint, @bitCast(u32, -ex + 1)); | |
| 318 | } | |
| 319 | if (T == f32) { | |
| 320 | ux |= sx; | |
| 321 | } else { | |
| 322 | ux |= @intCast(uint, sx) << bits_minus_1; | |
| 323 | } | |
| 324 | return @bitCast(T, ux); | |
| 325 | } | |
| 326 | ||
| 327 | test "fmod, fmodf" { | |
| 328 | inline for ([_]type{ f32, f64 }) |T| { | |
| 329 | const nan_val = math.nan(T); | |
| 330 | const inf_val = math.inf(T); | |
| 331 | ||
| 332 | try std.testing.expect(math.isNan(generic_fmod(T, nan_val, 1.0))); | |
| 333 | try std.testing.expect(math.isNan(generic_fmod(T, 1.0, nan_val))); | |
| 334 | try std.testing.expect(math.isNan(generic_fmod(T, inf_val, 1.0))); | |
| 335 | try std.testing.expect(math.isNan(generic_fmod(T, 0.0, 0.0))); | |
| 336 | try std.testing.expect(math.isNan(generic_fmod(T, 1.0, 0.0))); | |
| 337 | ||
| 338 | try std.testing.expectEqual(@as(T, 0.0), generic_fmod(T, 0.0, 2.0)); | |
| 339 | try std.testing.expectEqual(@as(T, -0.0), generic_fmod(T, -0.0, 2.0)); | |
| 340 | ||
| 341 | try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, 10.0)); | |
| 342 | try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, -10.0)); | |
| 343 | try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, 10.0)); | |
| 344 | try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, -10.0)); | |
| 345 | } | |
| 346 | } | |
| 347 | ||
| 348 | test { | |
| 349 | _ = @import("fmodq_test.zig"); | |
| 350 | _ = @import("fmodx_test.zig"); | |
| 351 | } |
lib/std/special/compiler_rt/fmodq.zig deleted-126| ... | ... | @@ -1,126 +0,0 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | ||
| 4 | // fmodq - floating modulo large, returns the remainder of division for f128 types | |
| 5 | // Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits | |
| 6 | pub fn fmodq(a: f128, b: f128) callconv(.C) f128 { | |
| 7 | @setRuntimeSafety(builtin.is_test); | |
| 8 | var amod = a; | |
| 9 | var bmod = b; | |
| 10 | const aPtr_u64 = @ptrCast([*]u64, &amod); | |
| 11 | const bPtr_u64 = @ptrCast([*]u64, &bmod); | |
| 12 | const aPtr_u16 = @ptrCast([*]u16, &amod); | |
| 13 | const bPtr_u16 = @ptrCast([*]u16, &bmod); | |
| 14 | ||
| 15 | const exp_and_sign_index = comptime switch (builtin.target.cpu.arch.endian()) { | |
| 16 | .Little => 7, | |
| 17 | .Big => 0, | |
| 18 | }; | |
| 19 | const low_index = comptime switch (builtin.target.cpu.arch.endian()) { | |
| 20 | .Little => 0, | |
| 21 | .Big => 1, | |
| 22 | }; | |
| 23 | const high_index = comptime switch (builtin.target.cpu.arch.endian()) { | |
| 24 | .Little => 1, | |
| 25 | .Big => 0, | |
| 26 | }; | |
| 27 | ||
| 28 | const signA = aPtr_u16[exp_and_sign_index] & 0x8000; | |
| 29 | var expA = @intCast(i32, (aPtr_u16[exp_and_sign_index] & 0x7fff)); | |
| 30 | var expB = @intCast(i32, (bPtr_u16[exp_and_sign_index] & 0x7fff)); | |
| 31 | ||
| 32 | // There are 3 cases where the answer is undefined, check for: | |
| 33 | // - fmodq(val, 0) | |
| 34 | // - fmodq(val, NaN) | |
| 35 | // - fmodq(inf, val) | |
| 36 | // The sign on checked values does not matter. | |
| 37 | // Doing (a * b) / (a * b) procudes undefined results | |
| 38 | // because the three cases always produce undefined calculations: | |
| 39 | // - 0 / 0 | |
| 40 | // - val * NaN | |
| 41 | // - inf / inf | |
| 42 | if (b == 0 or std.math.isNan(b) or expA == 0x7fff) { | |
| 43 | return (a * b) / (a * b); | |
| 44 | } | |
| 45 | ||
| 46 | // Remove the sign from both | |
| 47 | aPtr_u16[exp_and_sign_index] = @bitCast(u16, @intCast(i16, expA)); | |
| 48 | bPtr_u16[exp_and_sign_index] = @bitCast(u16, @intCast(i16, expB)); | |
| 49 | if (amod <= bmod) { | |
| 50 | if (amod == bmod) { | |
| 51 | return 0 * a; | |
| 52 | } | |
| 53 | return a; | |
| 54 | } | |
| 55 | ||
| 56 | if (expA == 0) { | |
| 57 | amod *= 0x1p120; | |
| 58 | expA = @as(i32, aPtr_u16[exp_and_sign_index]) - 120; | |
| 59 | } | |
| 60 | ||
| 61 | if (expB == 0) { | |
| 62 | bmod *= 0x1p120; | |
| 63 | expB = @as(i32, bPtr_u16[exp_and_sign_index]) - 120; | |
| 64 | } | |
| 65 | ||
| 66 | // OR in extra non-stored mantissa digit | |
| 67 | var highA: u64 = (aPtr_u64[high_index] & (std.math.maxInt(u64) >> 16)) | 1 << 48; | |
| 68 | var highB: u64 = (bPtr_u64[high_index] & (std.math.maxInt(u64) >> 16)) | 1 << 48; | |
| 69 | var lowA: u64 = aPtr_u64[low_index]; | |
| 70 | var lowB: u64 = bPtr_u64[low_index]; | |
| 71 | ||
| 72 | while (expA > expB) : (expA -= 1) { | |
| 73 | var high = highA -% highB; | |
| 74 | var low = lowA -% lowB; | |
| 75 | if (lowA < lowB) { | |
| 76 | high -%= 1; | |
| 77 | } | |
| 78 | if (high >> 63 == 0) { | |
| 79 | if ((high | low) == 0) { | |
| 80 | return 0 * a; | |
| 81 | } | |
| 82 | highA = 2 *% high + (low >> 63); | |
| 83 | lowA = 2 *% low; | |
| 84 | } else { | |
| 85 | highA = 2 *% highA + (lowA >> 63); | |
| 86 | lowA = 2 *% lowA; | |
| 87 | } | |
| 88 | } | |
| 89 | ||
| 90 | var high = highA -% highB; | |
| 91 | var low = lowA -% lowB; | |
| 92 | if (lowA < lowB) { | |
| 93 | high -= 1; | |
| 94 | } | |
| 95 | if (high >> 63 == 0) { | |
| 96 | if ((high | low) == 0) { | |
| 97 | return 0 * a; | |
| 98 | } | |
| 99 | highA = high; | |
| 100 | lowA = low; | |
| 101 | } | |
| 102 | ||
| 103 | while (highA >> 48 == 0) { | |
| 104 | highA = 2 *% highA + (lowA >> 63); | |
| 105 | lowA = 2 *% lowA; | |
| 106 | expA = expA - 1; | |
| 107 | } | |
| 108 | ||
| 109 | // Overwrite the current amod with the values in highA and lowA | |
| 110 | aPtr_u64[high_index] = highA; | |
| 111 | aPtr_u64[low_index] = lowA; | |
| 112 | ||
| 113 | // Combine the exponent with the sign, normalize if happend to be denormalized | |
| 114 | if (expA <= 0) { | |
| 115 | aPtr_u16[exp_and_sign_index] = @truncate(u16, @bitCast(u32, (expA +% 120))) | signA; | |
| 116 | amod *= 0x1p-120; | |
| 117 | } else { | |
| 118 | aPtr_u16[exp_and_sign_index] = @truncate(u16, @bitCast(u32, expA)) | signA; | |
| 119 | } | |
| 120 | ||
| 121 | return amod; | |
| 122 | } | |
| 123 | ||
| 124 | test { | |
| 125 | _ = @import("fmodq_test.zig"); | |
| 126 | } |
lib/std/special/compiler_rt/fmodq_test.zig+10-10| ... | ... | @@ -1,24 +1,24 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const fmodq = @import("fmodq.zig"); | |
| 2 | const fmod = @import("fmod.zig"); | |
| 3 | 3 | const testing = std.testing; |
| 4 | 4 | |
| 5 | 5 | fn test_fmodq(a: f128, b: f128, exp: f128) !void { |
| 6 | const res = fmodq.fmodq(a, b); | |
| 6 | const res = fmod.fmodq(a, b); | |
| 7 | 7 | try testing.expect(exp == res); |
| 8 | 8 | } |
| 9 | 9 | |
| 10 | 10 | fn test_fmodq_nans() !void { |
| 11 | try testing.expect(std.math.isNan(fmodq.fmodq(1.0, std.math.nan(f128)))); | |
| 12 | try testing.expect(std.math.isNan(fmodq.fmodq(1.0, -std.math.nan(f128)))); | |
| 13 | try testing.expect(std.math.isNan(fmodq.fmodq(std.math.nan(f128), 1.0))); | |
| 14 | try testing.expect(std.math.isNan(fmodq.fmodq(-std.math.nan(f128), 1.0))); | |
| 11 | try testing.expect(std.math.isNan(fmod.fmodq(1.0, std.math.nan(f128)))); | |
| 12 | try testing.expect(std.math.isNan(fmod.fmodq(1.0, -std.math.nan(f128)))); | |
| 13 | try testing.expect(std.math.isNan(fmod.fmodq(std.math.nan(f128), 1.0))); | |
| 14 | try testing.expect(std.math.isNan(fmod.fmodq(-std.math.nan(f128), 1.0))); | |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | fn test_fmodq_infs() !void { |
| 18 | try testing.expect(fmodq.fmodq(1.0, std.math.inf(f128)) == 1.0); | |
| 19 | try testing.expect(fmodq.fmodq(1.0, -std.math.inf(f128)) == 1.0); | |
| 20 | try testing.expect(std.math.isNan(fmodq.fmodq(std.math.inf(f128), 1.0))); | |
| 21 | try testing.expect(std.math.isNan(fmodq.fmodq(-std.math.inf(f128), 1.0))); | |
| 18 | try testing.expect(fmod.fmodq(1.0, std.math.inf(f128)) == 1.0); | |
| 19 | try testing.expect(fmod.fmodq(1.0, -std.math.inf(f128)) == 1.0); | |
| 20 | try testing.expect(std.math.isNan(fmod.fmodq(std.math.inf(f128), 1.0))); | |
| 21 | try testing.expect(std.math.isNan(fmod.fmodq(-std.math.inf(f128), 1.0))); | |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | 24 | test "fmodq" { |
lib/std/special/compiler_rt/fmodx.zig deleted-108| ... | ... | @@ -1,108 +0,0 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const math = std.math; | |
| 4 | const normalize = @import("divdf3.zig").normalize; | |
| 5 | ||
| 6 | // fmodx - floating modulo large, returns the remainder of division for f80 types | |
| 7 | // Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits | |
| 8 | pub fn fmodx(a: f80, b: f80) callconv(.C) f80 { | |
| 9 | @setRuntimeSafety(builtin.is_test); | |
| 10 | ||
| 11 | const T = f80; | |
| 12 | const Z = std.meta.Int(.unsigned, @bitSizeOf(T)); | |
| 13 | ||
| 14 | const significandBits = math.floatMantissaBits(T); | |
| 15 | const fractionalBits = math.floatFractionalBits(T); | |
| 16 | const exponentBits = math.floatExponentBits(T); | |
| 17 | ||
| 18 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); | |
| 19 | const maxExponent = ((1 << exponentBits) - 1); | |
| 20 | ||
| 21 | var aRep = @bitCast(Z, a); | |
| 22 | var bRep = @bitCast(Z, b); | |
| 23 | ||
| 24 | const signA = aRep & signBit; | |
| 25 | var expA = @intCast(i32, (@bitCast(Z, a) >> significandBits) & maxExponent); | |
| 26 | var expB = @intCast(i32, (@bitCast(Z, b) >> significandBits) & maxExponent); | |
| 27 | ||
| 28 | // There are 3 cases where the answer is undefined, check for: | |
| 29 | // - fmodx(val, 0) | |
| 30 | // - fmodx(val, NaN) | |
| 31 | // - fmodx(inf, val) | |
| 32 | // The sign on checked values does not matter. | |
| 33 | // Doing (a * b) / (a * b) procudes undefined results | |
| 34 | // because the three cases always produce undefined calculations: | |
| 35 | // - 0 / 0 | |
| 36 | // - val * NaN | |
| 37 | // - inf / inf | |
| 38 | if (b == 0 or math.isNan(b) or expA == maxExponent) { | |
| 39 | return (a * b) / (a * b); | |
| 40 | } | |
| 41 | ||
| 42 | // Remove the sign from both | |
| 43 | aRep &= ~signBit; | |
| 44 | bRep &= ~signBit; | |
| 45 | if (aRep <= bRep) { | |
| 46 | if (aRep == bRep) { | |
| 47 | return 0 * a; | |
| 48 | } | |
| 49 | return a; | |
| 50 | } | |
| 51 | ||
| 52 | if (expA == 0) expA = normalize(f80, &aRep); | |
| 53 | if (expB == 0) expB = normalize(f80, &bRep); | |
| 54 | ||
| 55 | var highA: u64 = 0; | |
| 56 | var highB: u64 = 0; | |
| 57 | var lowA: u64 = @truncate(u64, aRep); | |
| 58 | var lowB: u64 = @truncate(u64, bRep); | |
| 59 | ||
| 60 | while (expA > expB) : (expA -= 1) { | |
| 61 | var high = highA -% highB; | |
| 62 | var low = lowA -% lowB; | |
| 63 | if (lowA < lowB) { | |
| 64 | high -%= 1; | |
| 65 | } | |
| 66 | if (high >> 63 == 0) { | |
| 67 | if ((high | low) == 0) { | |
| 68 | return 0 * a; | |
| 69 | } | |
| 70 | highA = 2 *% high + (low >> 63); | |
| 71 | lowA = 2 *% low; | |
| 72 | } else { | |
| 73 | highA = 2 *% highA + (lowA >> 63); | |
| 74 | lowA = 2 *% lowA; | |
| 75 | } | |
| 76 | } | |
| 77 | ||
| 78 | var high = highA -% highB; | |
| 79 | var low = lowA -% lowB; | |
| 80 | if (lowA < lowB) { | |
| 81 | high -%= 1; | |
| 82 | } | |
| 83 | if (high >> 63 == 0) { | |
| 84 | if ((high | low) == 0) { | |
| 85 | return 0 * a; | |
| 86 | } | |
| 87 | highA = high; | |
| 88 | lowA = low; | |
| 89 | } | |
| 90 | ||
| 91 | while ((lowA >> fractionalBits) == 0) { | |
| 92 | lowA = 2 *% lowA; | |
| 93 | expA = expA - 1; | |
| 94 | } | |
| 95 | ||
| 96 | // Combine the exponent with the sign and significand, normalize if happened to be denormalized | |
| 97 | if (expA < -fractionalBits) { | |
| 98 | return @bitCast(T, signA); | |
| 99 | } else if (expA <= 0) { | |
| 100 | return @bitCast(T, (lowA >> @intCast(math.Log2Int(u64), 1 - expA)) | signA); | |
| 101 | } else { | |
| 102 | return @bitCast(T, lowA | (@as(Z, @intCast(u16, expA)) << significandBits) | signA); | |
| 103 | } | |
| 104 | } | |
| 105 | ||
| 106 | test { | |
| 107 | _ = @import("fmodx_test.zig"); | |
| 108 | } |
lib/std/special/compiler_rt/fmodx_test.zig+10-10| ... | ... | @@ -1,24 +1,24 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const fmodx = @import("fmodx.zig"); | |
| 2 | const fmod = @import("fmod.zig"); | |
| 3 | 3 | const testing = std.testing; |
| 4 | 4 | |
| 5 | 5 | fn test_fmodx(a: f80, b: f80, exp: f80) !void { |
| 6 | const res = fmodx.fmodx(a, b); | |
| 6 | const res = fmod.__fmodx(a, b); | |
| 7 | 7 | try testing.expect(exp == res); |
| 8 | 8 | } |
| 9 | 9 | |
| 10 | 10 | fn test_fmodx_nans() !void { |
| 11 | try testing.expect(std.math.isNan(fmodx.fmodx(1.0, std.math.nan(f80)))); | |
| 12 | try testing.expect(std.math.isNan(fmodx.fmodx(1.0, -std.math.nan(f80)))); | |
| 13 | try testing.expect(std.math.isNan(fmodx.fmodx(std.math.nan(f80), 1.0))); | |
| 14 | try testing.expect(std.math.isNan(fmodx.fmodx(-std.math.nan(f80), 1.0))); | |
| 11 | try testing.expect(std.math.isNan(fmod.__fmodx(1.0, std.math.nan(f80)))); | |
| 12 | try testing.expect(std.math.isNan(fmod.__fmodx(1.0, -std.math.nan(f80)))); | |
| 13 | try testing.expect(std.math.isNan(fmod.__fmodx(std.math.nan(f80), 1.0))); | |
| 14 | try testing.expect(std.math.isNan(fmod.__fmodx(-std.math.nan(f80), 1.0))); | |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | fn test_fmodx_infs() !void { |
| 18 | try testing.expect(fmodx.fmodx(1.0, std.math.inf(f80)) == 1.0); | |
| 19 | try testing.expect(fmodx.fmodx(1.0, -std.math.inf(f80)) == 1.0); | |
| 20 | try testing.expect(std.math.isNan(fmodx.fmodx(std.math.inf(f80), 1.0))); | |
| 21 | try testing.expect(std.math.isNan(fmodx.fmodx(-std.math.inf(f80), 1.0))); | |
| 18 | try testing.expect(fmod.__fmodx(1.0, std.math.inf(f80)) == 1.0); | |
| 19 | try testing.expect(fmod.__fmodx(1.0, -std.math.inf(f80)) == 1.0); | |
| 20 | try testing.expect(std.math.isNan(fmod.__fmodx(std.math.inf(f80), 1.0))); | |
| 21 | try testing.expect(std.math.isNan(fmod.__fmodx(-std.math.inf(f80), 1.0))); | |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | 24 | test "fmodx" { |
lib/std/special/compiler_rt/log.zig created+168| ... | ... | @@ -0,0 +1,168 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/lnf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ln.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const testing = std.testing; | |
| 10 | ||
| 11 | pub fn __logh(a: f16) callconv(.C) f16 { | |
| 12 | // TODO: more efficient implementation | |
| 13 | return @floatCast(f16, logf(a)); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn logf(x_: f32) callconv(.C) f32 { | |
| 17 | const ln2_hi: f32 = 6.9313812256e-01; | |
| 18 | const ln2_lo: f32 = 9.0580006145e-06; | |
| 19 | const Lg1: f32 = 0xaaaaaa.0p-24; | |
| 20 | const Lg2: f32 = 0xccce13.0p-25; | |
| 21 | const Lg3: f32 = 0x91e9ee.0p-25; | |
| 22 | const Lg4: f32 = 0xf89e26.0p-26; | |
| 23 | ||
| 24 | var x = x_; | |
| 25 | var ix = @bitCast(u32, x); | |
| 26 | var k: i32 = 0; | |
| 27 | ||
| 28 | // x < 2^(-126) | |
| 29 | if (ix < 0x00800000 or ix >> 31 != 0) { | |
| 30 | // log(+-0) = -inf | |
| 31 | if (ix << 1 == 0) { | |
| 32 | return -math.inf(f32); | |
| 33 | } | |
| 34 | // log(-#) = nan | |
| 35 | if (ix >> 31 != 0) { | |
| 36 | return math.nan(f32); | |
| 37 | } | |
| 38 | ||
| 39 | // subnormal, scale x | |
| 40 | k -= 25; | |
| 41 | x *= 0x1.0p25; | |
| 42 | ix = @bitCast(u32, x); | |
| 43 | } else if (ix >= 0x7F800000) { | |
| 44 | return x; | |
| 45 | } else if (ix == 0x3F800000) { | |
| 46 | return 0; | |
| 47 | } | |
| 48 | ||
| 49 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 50 | ix += 0x3F800000 - 0x3F3504F3; | |
| 51 | k += @intCast(i32, ix >> 23) - 0x7F; | |
| 52 | ix = (ix & 0x007FFFFF) + 0x3F3504F3; | |
| 53 | x = @bitCast(f32, ix); | |
| 54 | ||
| 55 | const f = x - 1.0; | |
| 56 | const s = f / (2.0 + f); | |
| 57 | const z = s * s; | |
| 58 | const w = z * z; | |
| 59 | const t1 = w * (Lg2 + w * Lg4); | |
| 60 | const t2 = z * (Lg1 + w * Lg3); | |
| 61 | const R = t2 + t1; | |
| 62 | const hfsq = 0.5 * f * f; | |
| 63 | const dk = @intToFloat(f32, k); | |
| 64 | ||
| 65 | return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; | |
| 66 | } | |
| 67 | ||
| 68 | pub fn log(x_: f64) callconv(.C) f64 { | |
| 69 | const ln2_hi: f64 = 6.93147180369123816490e-01; | |
| 70 | const ln2_lo: f64 = 1.90821492927058770002e-10; | |
| 71 | const Lg1: f64 = 6.666666666666735130e-01; | |
| 72 | const Lg2: f64 = 3.999999999940941908e-01; | |
| 73 | const Lg3: f64 = 2.857142874366239149e-01; | |
| 74 | const Lg4: f64 = 2.222219843214978396e-01; | |
| 75 | const Lg5: f64 = 1.818357216161805012e-01; | |
| 76 | const Lg6: f64 = 1.531383769920937332e-01; | |
| 77 | const Lg7: f64 = 1.479819860511658591e-01; | |
| 78 | ||
| 79 | var x = x_; | |
| 80 | var ix = @bitCast(u64, x); | |
| 81 | var hx = @intCast(u32, ix >> 32); | |
| 82 | var k: i32 = 0; | |
| 83 | ||
| 84 | if (hx < 0x00100000 or hx >> 31 != 0) { | |
| 85 | // log(+-0) = -inf | |
| 86 | if (ix << 1 == 0) { | |
| 87 | return -math.inf(f64); | |
| 88 | } | |
| 89 | // log(-#) = nan | |
| 90 | if (hx >> 31 != 0) { | |
| 91 | return math.nan(f64); | |
| 92 | } | |
| 93 | ||
| 94 | // subnormal, scale x | |
| 95 | k -= 54; | |
| 96 | x *= 0x1.0p54; | |
| 97 | hx = @intCast(u32, @bitCast(u64, ix) >> 32); | |
| 98 | } else if (hx >= 0x7FF00000) { | |
| 99 | return x; | |
| 100 | } else if (hx == 0x3FF00000 and ix << 32 == 0) { | |
| 101 | return 0; | |
| 102 | } | |
| 103 | ||
| 104 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 105 | hx += 0x3FF00000 - 0x3FE6A09E; | |
| 106 | k += @intCast(i32, hx >> 20) - 0x3FF; | |
| 107 | hx = (hx & 0x000FFFFF) + 0x3FE6A09E; | |
| 108 | ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF); | |
| 109 | x = @bitCast(f64, ix); | |
| 110 | ||
| 111 | const f = x - 1.0; | |
| 112 | const hfsq = 0.5 * f * f; | |
| 113 | const s = f / (2.0 + f); | |
| 114 | const z = s * s; | |
| 115 | const w = z * z; | |
| 116 | const t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); | |
| 117 | const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); | |
| 118 | const R = t2 + t1; | |
| 119 | const dk = @intToFloat(f64, k); | |
| 120 | ||
| 121 | return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; | |
| 122 | } | |
| 123 | ||
| 124 | pub fn __logx(a: f80) callconv(.C) f80 { | |
| 125 | // TODO: more efficient implementation | |
| 126 | return @floatCast(f80, logq(a)); | |
| 127 | } | |
| 128 | ||
| 129 | pub fn logq(a: f128) callconv(.C) f128 { | |
| 130 | // TODO: more correct implementation | |
| 131 | return log(@floatCast(f64, a)); | |
| 132 | } | |
| 133 | ||
| 134 | test "ln32" { | |
| 135 | const epsilon = 0.000001; | |
| 136 | ||
| 137 | try testing.expect(math.approxEqAbs(f32, logf(0.2), -1.609438, epsilon)); | |
| 138 | try testing.expect(math.approxEqAbs(f32, logf(0.8923), -0.113953, epsilon)); | |
| 139 | try testing.expect(math.approxEqAbs(f32, logf(1.5), 0.405465, epsilon)); | |
| 140 | try testing.expect(math.approxEqAbs(f32, logf(37.45), 3.623007, epsilon)); | |
| 141 | try testing.expect(math.approxEqAbs(f32, logf(89.123), 4.490017, epsilon)); | |
| 142 | try testing.expect(math.approxEqAbs(f32, logf(123123.234375), 11.720941, epsilon)); | |
| 143 | } | |
| 144 | ||
| 145 | test "ln64" { | |
| 146 | const epsilon = 0.000001; | |
| 147 | ||
| 148 | try testing.expect(math.approxEqAbs(f64, log(0.2), -1.609438, epsilon)); | |
| 149 | try testing.expect(math.approxEqAbs(f64, log(0.8923), -0.113953, epsilon)); | |
| 150 | try testing.expect(math.approxEqAbs(f64, log(1.5), 0.405465, epsilon)); | |
| 151 | try testing.expect(math.approxEqAbs(f64, log(37.45), 3.623007, epsilon)); | |
| 152 | try testing.expect(math.approxEqAbs(f64, log(89.123), 4.490017, epsilon)); | |
| 153 | try testing.expect(math.approxEqAbs(f64, log(123123.234375), 11.720941, epsilon)); | |
| 154 | } | |
| 155 | ||
| 156 | test "ln32.special" { | |
| 157 | try testing.expect(math.isPositiveInf(logf(math.inf(f32)))); | |
| 158 | try testing.expect(math.isNegativeInf(logf(0.0))); | |
| 159 | try testing.expect(math.isNan(logf(-1.0))); | |
| 160 | try testing.expect(math.isNan(logf(math.nan(f32)))); | |
| 161 | } | |
| 162 | ||
| 163 | test "ln64.special" { | |
| 164 | try testing.expect(math.isPositiveInf(log(math.inf(f64)))); | |
| 165 | try testing.expect(math.isNegativeInf(log(0.0))); | |
| 166 | try testing.expect(math.isNan(log(-1.0))); | |
| 167 | try testing.expect(math.isNan(log(math.nan(f64)))); | |
| 168 | } |
lib/std/special/compiler_rt/log10.zig created+196| ... | ... | @@ -0,0 +1,196 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log10f.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log10.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const testing = std.testing; | |
| 10 | const maxInt = std.math.maxInt; | |
| 11 | ||
| 12 | pub fn __log10h(a: f16) callconv(.C) f16 { | |
| 13 | // TODO: more efficient implementation | |
| 14 | return @floatCast(f16, log10f(a)); | |
| 15 | } | |
| 16 | ||
| 17 | pub fn log10f(x_: f32) callconv(.C) f32 { | |
| 18 | const ivln10hi: f32 = 4.3432617188e-01; | |
| 19 | const ivln10lo: f32 = -3.1689971365e-05; | |
| 20 | const log10_2hi: f32 = 3.0102920532e-01; | |
| 21 | const log10_2lo: f32 = 7.9034151668e-07; | |
| 22 | const Lg1: f32 = 0xaaaaaa.0p-24; | |
| 23 | const Lg2: f32 = 0xccce13.0p-25; | |
| 24 | const Lg3: f32 = 0x91e9ee.0p-25; | |
| 25 | const Lg4: f32 = 0xf89e26.0p-26; | |
| 26 | ||
| 27 | var x = x_; | |
| 28 | var u = @bitCast(u32, x); | |
| 29 | var ix = u; | |
| 30 | var k: i32 = 0; | |
| 31 | ||
| 32 | // x < 2^(-126) | |
| 33 | if (ix < 0x00800000 or ix >> 31 != 0) { | |
| 34 | // log(+-0) = -inf | |
| 35 | if (ix << 1 == 0) { | |
| 36 | return -math.inf(f32); | |
| 37 | } | |
| 38 | // log(-#) = nan | |
| 39 | if (ix >> 31 != 0) { | |
| 40 | return math.nan(f32); | |
| 41 | } | |
| 42 | ||
| 43 | k -= 25; | |
| 44 | x *= 0x1.0p25; | |
| 45 | ix = @bitCast(u32, x); | |
| 46 | } else if (ix >= 0x7F800000) { | |
| 47 | return x; | |
| 48 | } else if (ix == 0x3F800000) { | |
| 49 | return 0; | |
| 50 | } | |
| 51 | ||
| 52 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 53 | ix += 0x3F800000 - 0x3F3504F3; | |
| 54 | k += @intCast(i32, ix >> 23) - 0x7F; | |
| 55 | ix = (ix & 0x007FFFFF) + 0x3F3504F3; | |
| 56 | x = @bitCast(f32, ix); | |
| 57 | ||
| 58 | const f = x - 1.0; | |
| 59 | const s = f / (2.0 + f); | |
| 60 | const z = s * s; | |
| 61 | const w = z * z; | |
| 62 | const t1 = w * (Lg2 + w * Lg4); | |
| 63 | const t2 = z * (Lg1 + w * Lg3); | |
| 64 | const R = t2 + t1; | |
| 65 | const hfsq = 0.5 * f * f; | |
| 66 | ||
| 67 | var hi = f - hfsq; | |
| 68 | u = @bitCast(u32, hi); | |
| 69 | u &= 0xFFFFF000; | |
| 70 | hi = @bitCast(f32, u); | |
| 71 | const lo = f - hi - hfsq + s * (hfsq + R); | |
| 72 | const dk = @intToFloat(f32, k); | |
| 73 | ||
| 74 | return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi; | |
| 75 | } | |
| 76 | ||
| 77 | pub fn log10(x_: f64) callconv(.C) f64 { | |
| 78 | const ivln10hi: f64 = 4.34294481878168880939e-01; | |
| 79 | const ivln10lo: f64 = 2.50829467116452752298e-11; | |
| 80 | const log10_2hi: f64 = 3.01029995663611771306e-01; | |
| 81 | const log10_2lo: f64 = 3.69423907715893078616e-13; | |
| 82 | const Lg1: f64 = 6.666666666666735130e-01; | |
| 83 | const Lg2: f64 = 3.999999999940941908e-01; | |
| 84 | const Lg3: f64 = 2.857142874366239149e-01; | |
| 85 | const Lg4: f64 = 2.222219843214978396e-01; | |
| 86 | const Lg5: f64 = 1.818357216161805012e-01; | |
| 87 | const Lg6: f64 = 1.531383769920937332e-01; | |
| 88 | const Lg7: f64 = 1.479819860511658591e-01; | |
| 89 | ||
| 90 | var x = x_; | |
| 91 | var ix = @bitCast(u64, x); | |
| 92 | var hx = @intCast(u32, ix >> 32); | |
| 93 | var k: i32 = 0; | |
| 94 | ||
| 95 | if (hx < 0x00100000 or hx >> 31 != 0) { | |
| 96 | // log(+-0) = -inf | |
| 97 | if (ix << 1 == 0) { | |
| 98 | return -math.inf(f32); | |
| 99 | } | |
| 100 | // log(-#) = nan | |
| 101 | if (hx >> 31 != 0) { | |
| 102 | return math.nan(f32); | |
| 103 | } | |
| 104 | ||
| 105 | // subnormal, scale x | |
| 106 | k -= 54; | |
| 107 | x *= 0x1.0p54; | |
| 108 | hx = @intCast(u32, @bitCast(u64, x) >> 32); | |
| 109 | } else if (hx >= 0x7FF00000) { | |
| 110 | return x; | |
| 111 | } else if (hx == 0x3FF00000 and ix << 32 == 0) { | |
| 112 | return 0; | |
| 113 | } | |
| 114 | ||
| 115 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 116 | hx += 0x3FF00000 - 0x3FE6A09E; | |
| 117 | k += @intCast(i32, hx >> 20) - 0x3FF; | |
| 118 | hx = (hx & 0x000FFFFF) + 0x3FE6A09E; | |
| 119 | ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF); | |
| 120 | x = @bitCast(f64, ix); | |
| 121 | ||
| 122 | const f = x - 1.0; | |
| 123 | const hfsq = 0.5 * f * f; | |
| 124 | const s = f / (2.0 + f); | |
| 125 | const z = s * s; | |
| 126 | const w = z * z; | |
| 127 | const t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); | |
| 128 | const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); | |
| 129 | const R = t2 + t1; | |
| 130 | ||
| 131 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) | |
| 132 | var hi = f - hfsq; | |
| 133 | var hii = @bitCast(u64, hi); | |
| 134 | hii &= @as(u64, maxInt(u64)) << 32; | |
| 135 | hi = @bitCast(f64, hii); | |
| 136 | const lo = f - hi - hfsq + s * (hfsq + R); | |
| 137 | ||
| 138 | // val_hi + val_lo ~ log10(1 + f) + k * log10(2) | |
| 139 | var val_hi = hi * ivln10hi; | |
| 140 | const dk = @intToFloat(f64, k); | |
| 141 | const y = dk * log10_2hi; | |
| 142 | var val_lo = dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi; | |
| 143 | ||
| 144 | // Extra precision multiplication | |
| 145 | const ww = y + val_hi; | |
| 146 | val_lo += (y - ww) + val_hi; | |
| 147 | val_hi = ww; | |
| 148 | ||
| 149 | return val_lo + val_hi; | |
| 150 | } | |
| 151 | ||
| 152 | pub fn __log10x(a: f80) callconv(.C) f80 { | |
| 153 | // TODO: more efficient implementation | |
| 154 | return @floatCast(f80, log10q(a)); | |
| 155 | } | |
| 156 | ||
| 157 | pub fn log10q(a: f128) callconv(.C) f128 { | |
| 158 | // TODO: more correct implementation | |
| 159 | return log10(@floatCast(f64, a)); | |
| 160 | } | |
| 161 | ||
| 162 | test "log10_32" { | |
| 163 | const epsilon = 0.000001; | |
| 164 | ||
| 165 | try testing.expect(math.approxEqAbs(f32, log10f(0.2), -0.698970, epsilon)); | |
| 166 | try testing.expect(math.approxEqAbs(f32, log10f(0.8923), -0.049489, epsilon)); | |
| 167 | try testing.expect(math.approxEqAbs(f32, log10f(1.5), 0.176091, epsilon)); | |
| 168 | try testing.expect(math.approxEqAbs(f32, log10f(37.45), 1.573452, epsilon)); | |
| 169 | try testing.expect(math.approxEqAbs(f32, log10f(89.123), 1.94999, epsilon)); | |
| 170 | try testing.expect(math.approxEqAbs(f32, log10f(123123.234375), 5.09034, epsilon)); | |
| 171 | } | |
| 172 | ||
| 173 | test "log10_64" { | |
| 174 | const epsilon = 0.000001; | |
| 175 | ||
| 176 | try testing.expect(math.approxEqAbs(f64, log10(0.2), -0.698970, epsilon)); | |
| 177 | try testing.expect(math.approxEqAbs(f64, log10(0.8923), -0.049489, epsilon)); | |
| 178 | try testing.expect(math.approxEqAbs(f64, log10(1.5), 0.176091, epsilon)); | |
| 179 | try testing.expect(math.approxEqAbs(f64, log10(37.45), 1.573452, epsilon)); | |
| 180 | try testing.expect(math.approxEqAbs(f64, log10(89.123), 1.94999, epsilon)); | |
| 181 | try testing.expect(math.approxEqAbs(f64, log10(123123.234375), 5.09034, epsilon)); | |
| 182 | } | |
| 183 | ||
| 184 | test "log10_32.special" { | |
| 185 | try testing.expect(math.isPositiveInf(log10f(math.inf(f32)))); | |
| 186 | try testing.expect(math.isNegativeInf(log10f(0.0))); | |
| 187 | try testing.expect(math.isNan(log10f(-1.0))); | |
| 188 | try testing.expect(math.isNan(log10f(math.nan(f32)))); | |
| 189 | } | |
| 190 | ||
| 191 | test "log10_64.special" { | |
| 192 | try testing.expect(math.isPositiveInf(log10(math.inf(f64)))); | |
| 193 | try testing.expect(math.isNegativeInf(log10(0.0))); | |
| 194 | try testing.expect(math.isNan(log10(-1.0))); | |
| 195 | try testing.expect(math.isNan(log10(math.nan(f64)))); | |
| 196 | } |
lib/std/special/compiler_rt/log2.zig created+185| ... | ... | @@ -0,0 +1,185 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log2f.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log2.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | const maxInt = std.math.maxInt; | |
| 11 | ||
| 12 | pub fn __log2h(a: f16) callconv(.C) f16 { | |
| 13 | // TODO: more efficient implementation | |
| 14 | return @floatCast(f16, log2f(a)); | |
| 15 | } | |
| 16 | ||
| 17 | pub fn log2f(x_: f32) callconv(.C) f32 { | |
| 18 | const ivln2hi: f32 = 1.4428710938e+00; | |
| 19 | const ivln2lo: f32 = -1.7605285393e-04; | |
| 20 | const Lg1: f32 = 0xaaaaaa.0p-24; | |
| 21 | const Lg2: f32 = 0xccce13.0p-25; | |
| 22 | const Lg3: f32 = 0x91e9ee.0p-25; | |
| 23 | const Lg4: f32 = 0xf89e26.0p-26; | |
| 24 | ||
| 25 | var x = x_; | |
| 26 | var u = @bitCast(u32, x); | |
| 27 | var ix = u; | |
| 28 | var k: i32 = 0; | |
| 29 | ||
| 30 | // x < 2^(-126) | |
| 31 | if (ix < 0x00800000 or ix >> 31 != 0) { | |
| 32 | // log(+-0) = -inf | |
| 33 | if (ix << 1 == 0) { | |
| 34 | return -math.inf(f32); | |
| 35 | } | |
| 36 | // log(-#) = nan | |
| 37 | if (ix >> 31 != 0) { | |
| 38 | return math.nan(f32); | |
| 39 | } | |
| 40 | ||
| 41 | k -= 25; | |
| 42 | x *= 0x1.0p25; | |
| 43 | ix = @bitCast(u32, x); | |
| 44 | } else if (ix >= 0x7F800000) { | |
| 45 | return x; | |
| 46 | } else if (ix == 0x3F800000) { | |
| 47 | return 0; | |
| 48 | } | |
| 49 | ||
| 50 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 51 | ix += 0x3F800000 - 0x3F3504F3; | |
| 52 | k += @intCast(i32, ix >> 23) - 0x7F; | |
| 53 | ix = (ix & 0x007FFFFF) + 0x3F3504F3; | |
| 54 | x = @bitCast(f32, ix); | |
| 55 | ||
| 56 | const f = x - 1.0; | |
| 57 | const s = f / (2.0 + f); | |
| 58 | const z = s * s; | |
| 59 | const w = z * z; | |
| 60 | const t1 = w * (Lg2 + w * Lg4); | |
| 61 | const t2 = z * (Lg1 + w * Lg3); | |
| 62 | const R = t2 + t1; | |
| 63 | const hfsq = 0.5 * f * f; | |
| 64 | ||
| 65 | var hi = f - hfsq; | |
| 66 | u = @bitCast(u32, hi); | |
| 67 | u &= 0xFFFFF000; | |
| 68 | hi = @bitCast(f32, u); | |
| 69 | const lo = f - hi - hfsq + s * (hfsq + R); | |
| 70 | return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + @intToFloat(f32, k); | |
| 71 | } | |
| 72 | ||
| 73 | pub fn log2(x_: f64) callconv(.C) f64 { | |
| 74 | const ivln2hi: f64 = 1.44269504072144627571e+00; | |
| 75 | const ivln2lo: f64 = 1.67517131648865118353e-10; | |
| 76 | const Lg1: f64 = 6.666666666666735130e-01; | |
| 77 | const Lg2: f64 = 3.999999999940941908e-01; | |
| 78 | const Lg3: f64 = 2.857142874366239149e-01; | |
| 79 | const Lg4: f64 = 2.222219843214978396e-01; | |
| 80 | const Lg5: f64 = 1.818357216161805012e-01; | |
| 81 | const Lg6: f64 = 1.531383769920937332e-01; | |
| 82 | const Lg7: f64 = 1.479819860511658591e-01; | |
| 83 | ||
| 84 | var x = x_; | |
| 85 | var ix = @bitCast(u64, x); | |
| 86 | var hx = @intCast(u32, ix >> 32); | |
| 87 | var k: i32 = 0; | |
| 88 | ||
| 89 | if (hx < 0x00100000 or hx >> 31 != 0) { | |
| 90 | // log(+-0) = -inf | |
| 91 | if (ix << 1 == 0) { | |
| 92 | return -math.inf(f64); | |
| 93 | } | |
| 94 | // log(-#) = nan | |
| 95 | if (hx >> 31 != 0) { | |
| 96 | return math.nan(f64); | |
| 97 | } | |
| 98 | ||
| 99 | // subnormal, scale x | |
| 100 | k -= 54; | |
| 101 | x *= 0x1.0p54; | |
| 102 | hx = @intCast(u32, @bitCast(u64, x) >> 32); | |
| 103 | } else if (hx >= 0x7FF00000) { | |
| 104 | return x; | |
| 105 | } else if (hx == 0x3FF00000 and ix << 32 == 0) { | |
| 106 | return 0; | |
| 107 | } | |
| 108 | ||
| 109 | // x into [sqrt(2) / 2, sqrt(2)] | |
| 110 | hx += 0x3FF00000 - 0x3FE6A09E; | |
| 111 | k += @intCast(i32, hx >> 20) - 0x3FF; | |
| 112 | hx = (hx & 0x000FFFFF) + 0x3FE6A09E; | |
| 113 | ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF); | |
| 114 | x = @bitCast(f64, ix); | |
| 115 | ||
| 116 | const f = x - 1.0; | |
| 117 | const hfsq = 0.5 * f * f; | |
| 118 | const s = f / (2.0 + f); | |
| 119 | const z = s * s; | |
| 120 | const w = z * z; | |
| 121 | const t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); | |
| 122 | const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); | |
| 123 | const R = t2 + t1; | |
| 124 | ||
| 125 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) | |
| 126 | var hi = f - hfsq; | |
| 127 | var hii = @bitCast(u64, hi); | |
| 128 | hii &= @as(u64, maxInt(u64)) << 32; | |
| 129 | hi = @bitCast(f64, hii); | |
| 130 | const lo = f - hi - hfsq + s * (hfsq + R); | |
| 131 | ||
| 132 | var val_hi = hi * ivln2hi; | |
| 133 | var val_lo = (lo + hi) * ivln2lo + lo * ivln2hi; | |
| 134 | ||
| 135 | // spadd(val_hi, val_lo, y) | |
| 136 | const y = @intToFloat(f64, k); | |
| 137 | const ww = y + val_hi; | |
| 138 | val_lo += (y - ww) + val_hi; | |
| 139 | val_hi = ww; | |
| 140 | ||
| 141 | return val_lo + val_hi; | |
| 142 | } | |
| 143 | ||
| 144 | pub fn __log2x(a: f80) callconv(.C) f80 { | |
| 145 | // TODO: more efficient implementation | |
| 146 | return @floatCast(f80, log2q(a)); | |
| 147 | } | |
| 148 | ||
| 149 | pub fn log2q(a: f128) callconv(.C) f128 { | |
| 150 | return math.log2(a); | |
| 151 | } | |
| 152 | ||
| 153 | test "log2_32" { | |
| 154 | const epsilon = 0.000001; | |
| 155 | ||
| 156 | try expect(math.approxEqAbs(f32, log2f(0.2), -2.321928, epsilon)); | |
| 157 | try expect(math.approxEqAbs(f32, log2f(0.8923), -0.164399, epsilon)); | |
| 158 | try expect(math.approxEqAbs(f32, log2f(1.5), 0.584962, epsilon)); | |
| 159 | try expect(math.approxEqAbs(f32, log2f(37.45), 5.226894, epsilon)); | |
| 160 | try expect(math.approxEqAbs(f32, log2f(123123.234375), 16.909744, epsilon)); | |
| 161 | } | |
| 162 | ||
| 163 | test "log2_64" { | |
| 164 | const epsilon = 0.000001; | |
| 165 | ||
| 166 | try expect(math.approxEqAbs(f64, log2(0.2), -2.321928, epsilon)); | |
| 167 | try expect(math.approxEqAbs(f64, log2(0.8923), -0.164399, epsilon)); | |
| 168 | try expect(math.approxEqAbs(f64, log2(1.5), 0.584962, epsilon)); | |
| 169 | try expect(math.approxEqAbs(f64, log2(37.45), 5.226894, epsilon)); | |
| 170 | try expect(math.approxEqAbs(f64, log2(123123.234375), 16.909744, epsilon)); | |
| 171 | } | |
| 172 | ||
| 173 | test "log2_32.special" { | |
| 174 | try expect(math.isPositiveInf(log2f(math.inf(f32)))); | |
| 175 | try expect(math.isNegativeInf(log2f(0.0))); | |
| 176 | try expect(math.isNan(log2f(-1.0))); | |
| 177 | try expect(math.isNan(log2f(math.nan(f32)))); | |
| 178 | } | |
| 179 | ||
| 180 | test "log2_64.special" { | |
| 181 | try expect(math.isPositiveInf(log2(math.inf(f64)))); | |
| 182 | try expect(math.isNegativeInf(log2(0.0))); | |
| 183 | try expect(math.isNan(log2(-1.0))); | |
| 184 | try expect(math.isNan(log2(math.nan(f64)))); | |
| 185 | } |
lib/std/special/compiler_rt/rem_pio2.zig created+198| ... | ... | @@ -0,0 +1,198 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__rem_pio2.c | |
| 5 | ||
| 6 | const std = @import("std"); | |
| 7 | const rem_pio2_large = @import("rem_pio2_large.zig").rem_pio2_large; | |
| 8 | const math = std.math; | |
| 9 | ||
| 10 | const toint = 1.5 / math.floatEps(f64); | |
| 11 | // pi/4 | |
| 12 | const pio4 = 0x1.921fb54442d18p-1; | |
| 13 | // invpio2: 53 bits of 2/pi | |
| 14 | const invpio2 = 6.36619772367581382433e-01; // 0x3FE45F30, 0x6DC9C883 | |
| 15 | // pio2_1: first 33 bit of pi/2 | |
| 16 | const pio2_1 = 1.57079632673412561417e+00; // 0x3FF921FB, 0x54400000 | |
| 17 | // pio2_1t: pi/2 - pio2_1 | |
| 18 | const pio2_1t = 6.07710050650619224932e-11; // 0x3DD0B461, 0x1A626331 | |
| 19 | // pio2_2: second 33 bit of pi/2 | |
| 20 | const pio2_2 = 6.07710050630396597660e-11; // 0x3DD0B461, 0x1A600000 | |
| 21 | // pio2_2t: pi/2 - (pio2_1+pio2_2) | |
| 22 | const pio2_2t = 2.02226624879595063154e-21; // 0x3BA3198A, 0x2E037073 | |
| 23 | // pio2_3: third 33 bit of pi/2 | |
| 24 | const pio2_3 = 2.02226624871116645580e-21; // 0x3BA3198A, 0x2E000000 | |
| 25 | // pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) | |
| 26 | const pio2_3t = 8.47842766036889956997e-32; // 0x397B839A, 0x252049C1 | |
| 27 | ||
| 28 | fn U(x: anytype) usize { | |
| 29 | return @intCast(usize, x); | |
| 30 | } | |
| 31 | ||
| 32 | fn medium(ix: u32, x: f64, y: *[2]f64) i32 { | |
| 33 | var w: f64 = undefined; | |
| 34 | var t: f64 = undefined; | |
| 35 | var r: f64 = undefined; | |
| 36 | var @"fn": f64 = undefined; | |
| 37 | var n: i32 = undefined; | |
| 38 | var ex: i32 = undefined; | |
| 39 | var ey: i32 = undefined; | |
| 40 | var ui: u64 = undefined; | |
| 41 | ||
| 42 | // rint(x/(pi/2)) | |
| 43 | @"fn" = x * invpio2 + toint - toint; | |
| 44 | n = @floatToInt(i32, @"fn"); | |
| 45 | r = x - @"fn" * pio2_1; | |
| 46 | w = @"fn" * pio2_1t; // 1st round, good to 85 bits | |
| 47 | // Matters with directed rounding. | |
| 48 | if (r - w < -pio4) { | |
| 49 | n -= 1; | |
| 50 | @"fn" -= 1; | |
| 51 | r = x - @"fn" * pio2_1; | |
| 52 | w = @"fn" * pio2_1t; | |
| 53 | } else if (r - w > pio4) { | |
| 54 | n += 1; | |
| 55 | @"fn" += 1; | |
| 56 | r = x - @"fn" * pio2_1; | |
| 57 | w = @"fn" * pio2_1t; | |
| 58 | } | |
| 59 | y[0] = r - w; | |
| 60 | ui = @bitCast(u64, y[0]); | |
| 61 | ey = @intCast(i32, (ui >> 52) & 0x7ff); | |
| 62 | ex = @intCast(i32, ix >> 20); | |
| 63 | if (ex - ey > 16) { // 2nd round, good to 118 bits | |
| 64 | t = r; | |
| 65 | w = @"fn" * pio2_2; | |
| 66 | r = t - w; | |
| 67 | w = @"fn" * pio2_2t - ((t - r) - w); | |
| 68 | y[0] = r - w; | |
| 69 | ui = @bitCast(u64, y[0]); | |
| 70 | ey = @intCast(i32, (ui >> 52) & 0x7ff); | |
| 71 | if (ex - ey > 49) { // 3rd round, good to 151 bits, covers all cases | |
| 72 | t = r; | |
| 73 | w = @"fn" * pio2_3; | |
| 74 | r = t - w; | |
| 75 | w = @"fn" * pio2_3t - ((t - r) - w); | |
| 76 | y[0] = r - w; | |
| 77 | } | |
| 78 | } | |
| 79 | y[1] = (r - y[0]) - w; | |
| 80 | return n; | |
| 81 | } | |
| 82 | ||
| 83 | // Returns the remainder of x rem pi/2 in y[0]+y[1] | |
| 84 | // | |
| 85 | // use rem_pio2_large() for large x | |
| 86 | // | |
| 87 | // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ | |
| 88 | pub fn rem_pio2(x: f64, y: *[2]f64) i32 { | |
| 89 | var z: f64 = undefined; | |
| 90 | var tx: [3]f64 = undefined; | |
| 91 | var ty: [2]f64 = undefined; | |
| 92 | var n: i32 = undefined; | |
| 93 | var ix: u32 = undefined; | |
| 94 | var sign: bool = undefined; | |
| 95 | var i: i32 = undefined; | |
| 96 | var ui: u64 = undefined; | |
| 97 | ||
| 98 | ui = @bitCast(u64, x); | |
| 99 | sign = ui >> 63 != 0; | |
| 100 | ix = @truncate(u32, (ui >> 32) & 0x7fffffff); | |
| 101 | if (ix <= 0x400f6a7a) { // |x| ~<= 5pi/4 | |
| 102 | if ((ix & 0xfffff) == 0x921fb) { // |x| ~= pi/2 or 2pi/2 | |
| 103 | return medium(ix, x, y); | |
| 104 | } | |
| 105 | if (ix <= 0x4002d97c) { // |x| ~<= 3pi/4 | |
| 106 | if (!sign) { | |
| 107 | z = x - pio2_1; // one round good to 85 bits | |
| 108 | y[0] = z - pio2_1t; | |
| 109 | y[1] = (z - y[0]) - pio2_1t; | |
| 110 | return 1; | |
| 111 | } else { | |
| 112 | z = x + pio2_1; | |
| 113 | y[0] = z + pio2_1t; | |
| 114 | y[1] = (z - y[0]) + pio2_1t; | |
| 115 | return -1; | |
| 116 | } | |
| 117 | } else { | |
| 118 | if (!sign) { | |
| 119 | z = x - 2 * pio2_1; | |
| 120 | y[0] = z - 2 * pio2_1t; | |
| 121 | y[1] = (z - y[0]) - 2 * pio2_1t; | |
| 122 | return 2; | |
| 123 | } else { | |
| 124 | z = x + 2 * pio2_1; | |
| 125 | y[0] = z + 2 * pio2_1t; | |
| 126 | y[1] = (z - y[0]) + 2 * pio2_1t; | |
| 127 | return -2; | |
| 128 | } | |
| 129 | } | |
| 130 | } | |
| 131 | if (ix <= 0x401c463b) { // |x| ~<= 9pi/4 | |
| 132 | if (ix <= 0x4015fdbc) { // |x| ~<= 7pi/4 | |
| 133 | if (ix == 0x4012d97c) { // |x| ~= 3pi/2 | |
| 134 | return medium(ix, x, y); | |
| 135 | } | |
| 136 | if (!sign) { | |
| 137 | z = x - 3 * pio2_1; | |
| 138 | y[0] = z - 3 * pio2_1t; | |
| 139 | y[1] = (z - y[0]) - 3 * pio2_1t; | |
| 140 | return 3; | |
| 141 | } else { | |
| 142 | z = x + 3 * pio2_1; | |
| 143 | y[0] = z + 3 * pio2_1t; | |
| 144 | y[1] = (z - y[0]) + 3 * pio2_1t; | |
| 145 | return -3; | |
| 146 | } | |
| 147 | } else { | |
| 148 | if (ix == 0x401921fb) { // |x| ~= 4pi/2 */ | |
| 149 | return medium(ix, x, y); | |
| 150 | } | |
| 151 | if (!sign) { | |
| 152 | z = x - 4 * pio2_1; | |
| 153 | y[0] = z - 4 * pio2_1t; | |
| 154 | y[1] = (z - y[0]) - 4 * pio2_1t; | |
| 155 | return 4; | |
| 156 | } else { | |
| 157 | z = x + 4 * pio2_1; | |
| 158 | y[0] = z + 4 * pio2_1t; | |
| 159 | y[1] = (z - y[0]) + 4 * pio2_1t; | |
| 160 | return -4; | |
| 161 | } | |
| 162 | } | |
| 163 | } | |
| 164 | if (ix < 0x413921fb) { // |x| ~< 2^20*(pi/2), medium size | |
| 165 | return medium(ix, x, y); | |
| 166 | } | |
| 167 | // all other (large) arguments | |
| 168 | if (ix >= 0x7ff00000) { // x is inf or NaN | |
| 169 | y[0] = x - x; | |
| 170 | y[1] = y[0]; | |
| 171 | return 0; | |
| 172 | } | |
| 173 | // set z = scalbn(|x|,-ilogb(x)+23) | |
| 174 | ui = @bitCast(u64, x); | |
| 175 | ui &= std.math.maxInt(u64) >> 12; | |
| 176 | ui |= @as(u64, 0x3ff + 23) << 52; | |
| 177 | z = @bitCast(f64, ui); | |
| 178 | ||
| 179 | i = 0; | |
| 180 | while (i < 2) : (i += 1) { | |
| 181 | tx[U(i)] = @intToFloat(f64, @floatToInt(i32, z)); | |
| 182 | z = (z - tx[U(i)]) * 0x1p24; | |
| 183 | } | |
| 184 | tx[U(i)] = z; | |
| 185 | // skip zero terms, first term is non-zero | |
| 186 | while (tx[U(i)] == 0.0) { | |
| 187 | i -= 1; | |
| 188 | } | |
| 189 | n = rem_pio2_large(tx[0..], ty[0..], @intCast(i32, (ix >> 20)) - (0x3ff + 23), i + 1, 1); | |
| 190 | if (sign) { | |
| 191 | y[0] = -ty[0]; | |
| 192 | y[1] = -ty[1]; | |
| 193 | return -n; | |
| 194 | } | |
| 195 | y[0] = ty[0]; | |
| 196 | y[1] = ty[1]; | |
| 197 | return n; | |
| 198 | } |
lib/std/special/compiler_rt/rem_pio2_large.zig created+506| ... | ... | @@ -0,0 +1,506 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__rem_pio2_large.c | |
| 5 | ||
| 6 | const std = @import("std"); | |
| 7 | const math = std.math; | |
| 8 | ||
| 9 | const init_jk = [_]i32{ 3, 4, 4, 6 }; // initial value for jk | |
| 10 | ||
| 11 | /// | |
| 12 | /// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi | |
| 13 | /// | |
| 14 | /// integer array, contains the (24*i)-th to (24*i+23)-th | |
| 15 | /// bit of 2/pi after binary point. The corresponding | |
| 16 | /// floating value is | |
| 17 | /// | |
| 18 | /// ipio2[i] * 2^(-24(i+1)). | |
| 19 | /// | |
| 20 | /// NB: This table must have at least (e0-3)/24 + jk terms. | |
| 21 | /// For quad precision (e0 <= 16360, jk = 6), this is 686. | |
| 22 | const ipio2 = [_]i32{ | |
| 23 | 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, | |
| 24 | 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, | |
| 25 | 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, | |
| 26 | 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, | |
| 27 | 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, | |
| 28 | 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, | |
| 29 | 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, | |
| 30 | 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, | |
| 31 | 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, | |
| 32 | 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, | |
| 33 | 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, | |
| 34 | ||
| 35 | 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, | |
| 36 | 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, | |
| 37 | 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, | |
| 38 | 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, | |
| 39 | 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, | |
| 40 | 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, | |
| 41 | 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, | |
| 42 | 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, | |
| 43 | 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, | |
| 44 | 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, | |
| 45 | 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, | |
| 46 | 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, | |
| 47 | 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, | |
| 48 | 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, | |
| 49 | 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, | |
| 50 | 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, | |
| 51 | 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, | |
| 52 | 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, | |
| 53 | 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, | |
| 54 | 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, | |
| 55 | 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, | |
| 56 | 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, | |
| 57 | 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, | |
| 58 | 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, | |
| 59 | 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, | |
| 60 | 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, | |
| 61 | 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, | |
| 62 | 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, | |
| 63 | 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, | |
| 64 | 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, | |
| 65 | 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, | |
| 66 | 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, | |
| 67 | 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, | |
| 68 | 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, | |
| 69 | 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, | |
| 70 | 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, | |
| 71 | 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, | |
| 72 | 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, | |
| 73 | 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, | |
| 74 | 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, | |
| 75 | 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, | |
| 76 | 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, | |
| 77 | 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, | |
| 78 | 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, | |
| 79 | 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, | |
| 80 | 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, | |
| 81 | 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, | |
| 82 | 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, | |
| 83 | 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, | |
| 84 | 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, | |
| 85 | 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, | |
| 86 | 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, | |
| 87 | 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, | |
| 88 | 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, | |
| 89 | 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, | |
| 90 | 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, | |
| 91 | 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, | |
| 92 | 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, | |
| 93 | 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, | |
| 94 | 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, | |
| 95 | 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, | |
| 96 | 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, | |
| 97 | 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, | |
| 98 | 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, | |
| 99 | 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, | |
| 100 | 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, | |
| 101 | 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, | |
| 102 | 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, | |
| 103 | 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, | |
| 104 | 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, | |
| 105 | 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, | |
| 106 | 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, | |
| 107 | 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, | |
| 108 | 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, | |
| 109 | 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, | |
| 110 | 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, | |
| 111 | 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, | |
| 112 | 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, | |
| 113 | 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, | |
| 114 | 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, | |
| 115 | 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, | |
| 116 | 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, | |
| 117 | 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, | |
| 118 | 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, | |
| 119 | 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, | |
| 120 | 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, | |
| 121 | 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, | |
| 122 | 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, | |
| 123 | 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, | |
| 124 | 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, | |
| 125 | 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, | |
| 126 | 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, | |
| 127 | 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, | |
| 128 | 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, | |
| 129 | 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, | |
| 130 | 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, | |
| 131 | 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, | |
| 132 | 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, | |
| 133 | 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, | |
| 134 | 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, | |
| 135 | 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, | |
| 136 | 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, | |
| 137 | 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, | |
| 138 | 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, | |
| 139 | }; | |
| 140 | ||
| 141 | const PIo2 = [_]f64{ | |
| 142 | 1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000 | |
| 143 | 7.54978941586159635335e-08, // 0x3E74442D, 0x00000000 | |
| 144 | 5.39030252995776476554e-15, // 0x3CF84698, 0x80000000 | |
| 145 | 3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000 | |
| 146 | 1.27065575308067607349e-29, // 0x39F01B83, 0x80000000 | |
| 147 | 1.22933308981111328932e-36, // 0x387A2520, 0x40000000 | |
| 148 | 2.73370053816464559624e-44, // 0x36E38222, 0x80000000 | |
| 149 | 2.16741683877804819444e-51, // 0x3569F31D, 0x00000000 | |
| 150 | }; | |
| 151 | ||
| 152 | fn U(x: anytype) usize { | |
| 153 | return @intCast(usize, x); | |
| 154 | } | |
| 155 | ||
| 156 | /// Returns the last three digits of N with y = x - N*pi/2 so that |y| < pi/2. | |
| 157 | /// | |
| 158 | /// The method is to compute the integer (mod 8) and fraction parts of | |
| 159 | /// (2/pi)*x without doing the full multiplication. In general we | |
| 160 | /// skip the part of the product that are known to be a huge integer ( | |
| 161 | /// more accurately, = 0 mod 8 ). Thus the number of operations are | |
| 162 | /// independent of the exponent of the input. | |
| 163 | /// | |
| 164 | /// (2/pi) is represented by an array of 24-bit integers in ipio2[]. | |
| 165 | /// | |
| 166 | /// Input parameters: | |
| 167 | /// x[] The input value (must be positive) is broken into nx | |
| 168 | /// pieces of 24-bit integers in double precision format. | |
| 169 | /// x[i] will be the i-th 24 bit of x. The scaled exponent | |
| 170 | /// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 | |
| 171 | /// match x's up to 24 bits. | |
| 172 | /// | |
| 173 | /// Example of breaking a double positive z into x[0]+x[1]+x[2]: | |
| 174 | /// e0 = ilogb(z)-23 | |
| 175 | /// z = scalbn(z,-e0) | |
| 176 | /// for i = 0,1,2 | |
| 177 | /// x[i] = floor(z) | |
| 178 | /// z = (z-x[i])*2**24 | |
| 179 | /// | |
| 180 | /// | |
| 181 | /// y[] ouput result in an array of double precision numbers. | |
| 182 | /// The dimension of y[] is: | |
| 183 | /// 24-bit precision 1 | |
| 184 | /// 53-bit precision 2 | |
| 185 | /// 64-bit precision 2 | |
| 186 | /// 113-bit precision 3 | |
| 187 | /// The actual value is the sum of them. Thus for 113-bit | |
| 188 | /// precison, one may have to do something like: | |
| 189 | /// | |
| 190 | /// long double t,w,r_head, r_tail; | |
| 191 | /// t = (long double)y[2] + (long double)y[1]; | |
| 192 | /// w = (long double)y[0]; | |
| 193 | /// r_head = t+w; | |
| 194 | /// r_tail = w - (r_head - t); | |
| 195 | /// | |
| 196 | /// e0 The exponent of x[0]. Must be <= 16360 or you need to | |
| 197 | /// expand the ipio2 table. | |
| 198 | /// | |
| 199 | /// nx dimension of x[] | |
| 200 | /// | |
| 201 | /// prec an integer indicating the precision: | |
| 202 | /// 0 24 bits (single) | |
| 203 | /// 1 53 bits (double) | |
| 204 | /// 2 64 bits (extended) | |
| 205 | /// 3 113 bits (quad) | |
| 206 | /// | |
| 207 | /// Here is the description of some local variables: | |
| 208 | /// | |
| 209 | /// jk jk+1 is the initial number of terms of ipio2[] needed | |
| 210 | /// in the computation. The minimum and recommended value | |
| 211 | /// for jk is 3,4,4,6 for single, double, extended, and quad. | |
| 212 | /// jk+1 must be 2 larger than you might expect so that our | |
| 213 | /// recomputation test works. (Up to 24 bits in the integer | |
| 214 | /// part (the 24 bits of it that we compute) and 23 bits in | |
| 215 | /// the fraction part may be lost to cancelation before we | |
| 216 | /// recompute.) | |
| 217 | /// | |
| 218 | /// jz local integer variable indicating the number of | |
| 219 | /// terms of ipio2[] used. | |
| 220 | /// | |
| 221 | /// jx nx - 1 | |
| 222 | /// | |
| 223 | /// jv index for pointing to the suitable ipio2[] for the | |
| 224 | /// computation. In general, we want | |
| 225 | /// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 | |
| 226 | /// is an integer. Thus | |
| 227 | /// e0-3-24*jv >= 0 or (e0-3)/24 >= jv | |
| 228 | /// Hence jv = max(0,(e0-3)/24). | |
| 229 | /// | |
| 230 | /// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. | |
| 231 | /// | |
| 232 | /// q[] double array with integral value, representing the | |
| 233 | /// 24-bits chunk of the product of x and 2/pi. | |
| 234 | /// | |
| 235 | /// q0 the corresponding exponent of q[0]. Note that the | |
| 236 | /// exponent for q[i] would be q0-24*i. | |
| 237 | /// | |
| 238 | /// PIo2[] double precision array, obtained by cutting pi/2 | |
| 239 | /// into 24 bits chunks. | |
| 240 | /// | |
| 241 | /// f[] ipio2[] in floating point | |
| 242 | /// | |
| 243 | /// iq[] integer array by breaking up q[] in 24-bits chunk. | |
| 244 | /// | |
| 245 | /// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] | |
| 246 | /// | |
| 247 | /// ih integer. If >0 it indicates q[] is >= 0.5, hence | |
| 248 | /// it also indicates the *sign* of the result. | |
| 249 | /// | |
| 250 | /// | |
| 251 | /// | |
| 252 | /// Constants: | |
| 253 | /// The hexadecimal values are the intended ones for the following | |
| 254 | /// constants. The decimal values may be used, provided that the | |
| 255 | /// compiler will convert from decimal to binary accurately enough | |
| 256 | /// to produce the hexadecimal values shown. | |
| 257 | /// | |
| 258 | pub fn rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 { | |
| 259 | var jz: i32 = undefined; | |
| 260 | var jx: i32 = undefined; | |
| 261 | var jv: i32 = undefined; | |
| 262 | var jp: i32 = undefined; | |
| 263 | var jk: i32 = undefined; | |
| 264 | var carry: i32 = undefined; | |
| 265 | var n: i32 = undefined; | |
| 266 | var iq: [20]i32 = undefined; | |
| 267 | var i: i32 = undefined; | |
| 268 | var j: i32 = undefined; | |
| 269 | var k: i32 = undefined; | |
| 270 | var m: i32 = undefined; | |
| 271 | var q0: i32 = undefined; | |
| 272 | var ih: i32 = undefined; | |
| 273 | ||
| 274 | var z: f64 = undefined; | |
| 275 | var fw: f64 = undefined; | |
| 276 | var f: [20]f64 = undefined; | |
| 277 | var fq: [20]f64 = undefined; | |
| 278 | var q: [20]f64 = undefined; | |
| 279 | ||
| 280 | // initialize jk | |
| 281 | jk = init_jk[prec]; | |
| 282 | jp = jk; | |
| 283 | ||
| 284 | // determine jx,jv,q0, note that 3>q0 | |
| 285 | jx = nx - 1; | |
| 286 | jv = @divFloor(e0 - 3, 24); | |
| 287 | if (jv < 0) jv = 0; | |
| 288 | q0 = e0 - 24 * (jv + 1); | |
| 289 | ||
| 290 | // set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] | |
| 291 | j = jv - jx; | |
| 292 | m = jx + jk; | |
| 293 | i = 0; | |
| 294 | while (i <= m) : ({ | |
| 295 | i += 1; | |
| 296 | j += 1; | |
| 297 | }) { | |
| 298 | f[U(i)] = if (j < 0) 0.0 else @intToFloat(f64, ipio2[U(j)]); | |
| 299 | } | |
| 300 | ||
| 301 | // compute q[0],q[1],...q[jk] | |
| 302 | i = 0; | |
| 303 | while (i <= jk) : (i += 1) { | |
| 304 | j = 0; | |
| 305 | fw = 0; | |
| 306 | while (j <= jx) : (j += 1) { | |
| 307 | fw += x[U(j)] * f[U(jx + i - j)]; | |
| 308 | } | |
| 309 | q[U(i)] = fw; | |
| 310 | } | |
| 311 | ||
| 312 | jz = jk; | |
| 313 | ||
| 314 | // This is to handle a non-trivial goto translation from C. | |
| 315 | // An unconditional return statement is found at the end of this loop. | |
| 316 | recompute: while (true) { | |
| 317 | // distill q[] into iq[] reversingly | |
| 318 | i = 0; | |
| 319 | j = jz; | |
| 320 | z = q[U(jz)]; | |
| 321 | while (j > 0) : ({ | |
| 322 | i += 1; | |
| 323 | j -= 1; | |
| 324 | }) { | |
| 325 | fw = @intToFloat(f64, @floatToInt(i32, 0x1p-24 * z)); | |
| 326 | iq[U(i)] = @floatToInt(i32, z - 0x1p24 * fw); | |
| 327 | z = q[U(j - 1)] + fw; | |
| 328 | } | |
| 329 | ||
| 330 | // compute n | |
| 331 | z = math.scalbn(z, q0); // actual value of z | |
| 332 | z -= 8.0 * @floor(z * 0.125); // trim off integer >= 8 | |
| 333 | n = @floatToInt(i32, z); | |
| 334 | z -= @intToFloat(f64, n); | |
| 335 | ih = 0; | |
| 336 | if (q0 > 0) { // need iq[jz-1] to determine n | |
| 337 | i = iq[U(jz - 1)] >> @intCast(u5, 24 - q0); | |
| 338 | n += i; | |
| 339 | iq[U(jz - 1)] -= i << @intCast(u5, 24 - q0); | |
| 340 | ih = iq[U(jz - 1)] >> @intCast(u5, 23 - q0); | |
| 341 | } else if (q0 == 0) { | |
| 342 | ih = iq[U(jz - 1)] >> 23; | |
| 343 | } else if (z >= 0.5) { | |
| 344 | ih = 2; | |
| 345 | } | |
| 346 | ||
| 347 | if (ih > 0) { // q > 0.5 | |
| 348 | n += 1; | |
| 349 | carry = 0; | |
| 350 | i = 0; | |
| 351 | while (i < jz) : (i += 1) { // compute 1-q | |
| 352 | j = iq[U(i)]; | |
| 353 | if (carry == 0) { | |
| 354 | if (j != 0) { | |
| 355 | carry = 1; | |
| 356 | iq[U(i)] = 0x1000000 - j; | |
| 357 | } | |
| 358 | } else { | |
| 359 | iq[U(i)] = 0xffffff - j; | |
| 360 | } | |
| 361 | } | |
| 362 | if (q0 > 0) { // rare case: chance is 1 in 12 | |
| 363 | switch (q0) { | |
| 364 | 1 => iq[U(jz - 1)] &= 0x7fffff, | |
| 365 | 2 => iq[U(jz - 1)] &= 0x3fffff, | |
| 366 | else => unreachable, | |
| 367 | } | |
| 368 | } | |
| 369 | if (ih == 2) { | |
| 370 | z = 1.0 - z; | |
| 371 | if (carry != 0) { | |
| 372 | z -= math.scalbn(@as(f64, 1.0), q0); | |
| 373 | } | |
| 374 | } | |
| 375 | } | |
| 376 | ||
| 377 | // check if recomputation is needed | |
| 378 | if (z == 0.0) { | |
| 379 | j = 0; | |
| 380 | i = jz - 1; | |
| 381 | while (i >= jk) : (i -= 1) { | |
| 382 | j |= iq[U(i)]; | |
| 383 | } | |
| 384 | ||
| 385 | if (j == 0) { // need recomputation | |
| 386 | k = 1; | |
| 387 | while (iq[U(jk - k)] == 0) : (k += 1) { | |
| 388 | // k = no. of terms needed | |
| 389 | } | |
| 390 | ||
| 391 | i = jz + 1; | |
| 392 | while (i <= jz + k) : (i += 1) { // add q[jz+1] to q[jz+k] | |
| 393 | f[U(jx + i)] = @intToFloat(f64, ipio2[U(jv + i)]); | |
| 394 | j = 0; | |
| 395 | fw = 0; | |
| 396 | while (j <= jx) : (j += 1) { | |
| 397 | fw += x[U(j)] * f[U(jx + i - j)]; | |
| 398 | } | |
| 399 | q[U(i)] = fw; | |
| 400 | } | |
| 401 | jz += k; | |
| 402 | continue :recompute; // mimic goto recompute | |
| 403 | } | |
| 404 | } | |
| 405 | ||
| 406 | // chop off zero terms | |
| 407 | if (z == 0.0) { | |
| 408 | jz -= 1; | |
| 409 | q0 -= 24; | |
| 410 | while (iq[U(jz)] == 0) { | |
| 411 | jz -= 1; | |
| 412 | q0 -= 24; | |
| 413 | } | |
| 414 | } else { // break z into 24-bit if necessary | |
| 415 | z = math.scalbn(z, -q0); | |
| 416 | if (z >= 0x1p24) { | |
| 417 | fw = @intToFloat(f64, @floatToInt(i32, 0x1p-24 * z)); | |
| 418 | iq[U(jz)] = @floatToInt(i32, z - 0x1p24 * fw); | |
| 419 | jz += 1; | |
| 420 | q0 += 24; | |
| 421 | iq[U(jz)] = @floatToInt(i32, fw); | |
| 422 | } else { | |
| 423 | iq[U(jz)] = @floatToInt(i32, z); | |
| 424 | } | |
| 425 | } | |
| 426 | ||
| 427 | // convert integer "bit" chunk to floating-point value | |
| 428 | fw = math.scalbn(@as(f64, 1.0), q0); | |
| 429 | i = jz; | |
| 430 | while (i >= 0) : (i -= 1) { | |
| 431 | q[U(i)] = fw * @intToFloat(f64, iq[U(i)]); | |
| 432 | fw *= 0x1p-24; | |
| 433 | } | |
| 434 | ||
| 435 | // compute PIo2[0,...,jp]*q[jz,...,0] | |
| 436 | i = jz; | |
| 437 | while (i >= 0) : (i -= 1) { | |
| 438 | fw = 0; | |
| 439 | k = 0; | |
| 440 | while (k <= jp and k <= jz - i) : (k += 1) { | |
| 441 | fw += PIo2[U(k)] * q[U(i + k)]; | |
| 442 | } | |
| 443 | fq[U(jz - i)] = fw; | |
| 444 | } | |
| 445 | ||
| 446 | // compress fq[] into y[] | |
| 447 | switch (prec) { | |
| 448 | 0 => { | |
| 449 | fw = 0.0; | |
| 450 | i = jz; | |
| 451 | while (i >= 0) : (i -= 1) { | |
| 452 | fw += fq[U(i)]; | |
| 453 | } | |
| 454 | y[0] = if (ih == 0) fw else -fw; | |
| 455 | }, | |
| 456 | ||
| 457 | 1, 2 => { | |
| 458 | fw = 0.0; | |
| 459 | i = jz; | |
| 460 | while (i >= 0) : (i -= 1) { | |
| 461 | fw += fq[U(i)]; | |
| 462 | } | |
| 463 | // TODO: drop excess precision here once double_t is used | |
| 464 | fw = fw; | |
| 465 | y[0] = if (ih == 0) fw else -fw; | |
| 466 | fw = fq[0] - fw; | |
| 467 | i = 1; | |
| 468 | while (i <= jz) : (i += 1) { | |
| 469 | fw += fq[U(i)]; | |
| 470 | } | |
| 471 | y[1] = if (ih == 0) fw else -fw; | |
| 472 | }, | |
| 473 | 3 => { // painful | |
| 474 | i = jz; | |
| 475 | while (i > 0) : (i -= 1) { | |
| 476 | fw = fq[U(i - 1)] + fq[U(i)]; | |
| 477 | fq[U(i)] += fq[U(i - 1)] - fw; | |
| 478 | fq[U(i - 1)] = fw; | |
| 479 | } | |
| 480 | i = jz; | |
| 481 | while (i > 1) : (i -= 1) { | |
| 482 | fw = fq[U(i - 1)] + fq[U(i)]; | |
| 483 | fq[U(i)] += fq[U(i - 1)] - fw; | |
| 484 | fq[U(i - 1)] = fw; | |
| 485 | } | |
| 486 | fw = 0; | |
| 487 | i = jz; | |
| 488 | while (i >= 2) : (i -= 1) { | |
| 489 | fw += fq[U(i)]; | |
| 490 | } | |
| 491 | if (ih == 0) { | |
| 492 | y[0] = fq[0]; | |
| 493 | y[1] = fq[1]; | |
| 494 | y[2] = fw; | |
| 495 | } else { | |
| 496 | y[0] = -fq[0]; | |
| 497 | y[1] = -fq[1]; | |
| 498 | y[2] = -fw; | |
| 499 | } | |
| 500 | }, | |
| 501 | else => unreachable, | |
| 502 | } | |
| 503 | ||
| 504 | return n & 7; | |
| 505 | } | |
| 506 | } |
lib/std/special/compiler_rt/rem_pio2f.zig created+70| ... | ... | @@ -0,0 +1,70 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__rem_pio2f.c | |
| 5 | ||
| 6 | const std = @import("std"); | |
| 7 | const rem_pio2_large = @import("rem_pio2_large.zig").rem_pio2_large; | |
| 8 | const math = std.math; | |
| 9 | ||
| 10 | const toint = 1.5 / math.floatEps(f64); | |
| 11 | // pi/4 | |
| 12 | const pio4 = 0x1.921fb6p-1; | |
| 13 | // invpio2: 53 bits of 2/pi | |
| 14 | const invpio2 = 6.36619772367581382433e-01; // 0x3FE45F30, 0x6DC9C883 | |
| 15 | // pio2_1: first 25 bits of pi/2 | |
| 16 | const pio2_1 = 1.57079631090164184570e+00; // 0x3FF921FB, 0x50000000 | |
| 17 | // pio2_1t: pi/2 - pio2_1 | |
| 18 | const pio2_1t = 1.58932547735281966916e-08; // 0x3E5110b4, 0x611A6263 | |
| 19 | ||
| 20 | // Returns the remainder of x rem pi/2 in *y | |
| 21 | // use double precision for everything except passing x | |
| 22 | // use rem_pio2_large() for large x | |
| 23 | pub fn rem_pio2f(x: f32, y: *f64) i32 { | |
| 24 | var tx: [1]f64 = undefined; | |
| 25 | var ty: [1]f64 = undefined; | |
| 26 | var @"fn": f64 = undefined; | |
| 27 | var ix: u32 = undefined; | |
| 28 | var n: i32 = undefined; | |
| 29 | var sign: bool = undefined; | |
| 30 | var e0: u32 = undefined; | |
| 31 | var ui: u32 = undefined; | |
| 32 | ||
| 33 | ui = @bitCast(u32, x); | |
| 34 | ix = ui & 0x7fffffff; | |
| 35 | ||
| 36 | // 25+53 bit pi is good enough for medium size | |
| 37 | if (ix < 0x4dc90fdb) { // |x| ~< 2^28*(pi/2), medium size | |
| 38 | // Use a specialized rint() to get fn. | |
| 39 | @"fn" = @floatCast(f64, x) * invpio2 + toint - toint; | |
| 40 | n = @floatToInt(i32, @"fn"); | |
| 41 | y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t; | |
| 42 | // Matters with directed rounding. | |
| 43 | if (y.* < -pio4) { | |
| 44 | n -= 1; | |
| 45 | @"fn" -= 1; | |
| 46 | y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t; | |
| 47 | } else if (y.* > pio4) { | |
| 48 | n += 1; | |
| 49 | @"fn" += 1; | |
| 50 | y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t; | |
| 51 | } | |
| 52 | return n; | |
| 53 | } | |
| 54 | if (ix >= 0x7f800000) { // x is inf or NaN | |
| 55 | y.* = x - x; | |
| 56 | return 0; | |
| 57 | } | |
| 58 | // scale x into [2^23, 2^24-1] | |
| 59 | sign = ui >> 31 != 0; | |
| 60 | e0 = (ix >> 23) - (0x7f + 23); // e0 = ilogb(|x|)-23, positive | |
| 61 | ui = ix - (e0 << 23); | |
| 62 | tx[0] = @bitCast(f32, ui); | |
| 63 | n = rem_pio2_large(&tx, &ty, @intCast(i32, e0), 1, 0); | |
| 64 | if (sign) { | |
| 65 | y.* = -ty[0]; | |
| 66 | return -n; | |
| 67 | } | |
| 68 | y.* = ty[0]; | |
| 69 | return n; | |
| 70 | } |
lib/std/special/compiler_rt/round.zig created+169| ... | ... | @@ -0,0 +1,169 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/roundf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/round.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | pub fn __roundh(x: f16) callconv(.C) f16 { | |
| 12 | // TODO: more efficient implementation | |
| 13 | return @floatCast(f16, roundf(x)); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn roundf(x_: f32) callconv(.C) f32 { | |
| 17 | const f32_toint = 1.0 / math.floatEps(f32); | |
| 18 | ||
| 19 | var x = x_; | |
| 20 | const u = @bitCast(u32, x); | |
| 21 | const e = (u >> 23) & 0xFF; | |
| 22 | var y: f32 = undefined; | |
| 23 | ||
| 24 | if (e >= 0x7F + 23) { | |
| 25 | return x; | |
| 26 | } | |
| 27 | if (u >> 31 != 0) { | |
| 28 | x = -x; | |
| 29 | } | |
| 30 | if (e < 0x7F - 1) { | |
| 31 | math.doNotOptimizeAway(x + f32_toint); | |
| 32 | return 0 * @bitCast(f32, u); | |
| 33 | } | |
| 34 | ||
| 35 | y = x + f32_toint - f32_toint - x; | |
| 36 | if (y > 0.5) { | |
| 37 | y = y + x - 1; | |
| 38 | } else if (y <= -0.5) { | |
| 39 | y = y + x + 1; | |
| 40 | } else { | |
| 41 | y = y + x; | |
| 42 | } | |
| 43 | ||
| 44 | if (u >> 31 != 0) { | |
| 45 | return -y; | |
| 46 | } else { | |
| 47 | return y; | |
| 48 | } | |
| 49 | } | |
| 50 | ||
| 51 | pub fn round(x_: f64) callconv(.C) f64 { | |
| 52 | const f64_toint = 1.0 / math.floatEps(f64); | |
| 53 | ||
| 54 | var x = x_; | |
| 55 | const u = @bitCast(u64, x); | |
| 56 | const e = (u >> 52) & 0x7FF; | |
| 57 | var y: f64 = undefined; | |
| 58 | ||
| 59 | if (e >= 0x3FF + 52) { | |
| 60 | return x; | |
| 61 | } | |
| 62 | if (u >> 63 != 0) { | |
| 63 | x = -x; | |
| 64 | } | |
| 65 | if (e < 0x3ff - 1) { | |
| 66 | math.doNotOptimizeAway(x + f64_toint); | |
| 67 | return 0 * @bitCast(f64, u); | |
| 68 | } | |
| 69 | ||
| 70 | y = x + f64_toint - f64_toint - x; | |
| 71 | if (y > 0.5) { | |
| 72 | y = y + x - 1; | |
| 73 | } else if (y <= -0.5) { | |
| 74 | y = y + x + 1; | |
| 75 | } else { | |
| 76 | y = y + x; | |
| 77 | } | |
| 78 | ||
| 79 | if (u >> 63 != 0) { | |
| 80 | return -y; | |
| 81 | } else { | |
| 82 | return y; | |
| 83 | } | |
| 84 | } | |
| 85 | ||
| 86 | pub fn __roundx(x: f80) callconv(.C) f80 { | |
| 87 | // TODO: more efficient implementation | |
| 88 | return @floatCast(f80, roundq(x)); | |
| 89 | } | |
| 90 | ||
| 91 | pub fn roundq(x_: f128) callconv(.C) f128 { | |
| 92 | const f128_toint = 1.0 / math.floatEps(f128); | |
| 93 | ||
| 94 | var x = x_; | |
| 95 | const u = @bitCast(u128, x); | |
| 96 | const e = (u >> 112) & 0x7FFF; | |
| 97 | var y: f128 = undefined; | |
| 98 | ||
| 99 | if (e >= 0x3FFF + 112) { | |
| 100 | return x; | |
| 101 | } | |
| 102 | if (u >> 127 != 0) { | |
| 103 | x = -x; | |
| 104 | } | |
| 105 | if (e < 0x3FFF - 1) { | |
| 106 | math.doNotOptimizeAway(x + f128_toint); | |
| 107 | return 0 * @bitCast(f128, u); | |
| 108 | } | |
| 109 | ||
| 110 | y = x + f128_toint - f128_toint - x; | |
| 111 | if (y > 0.5) { | |
| 112 | y = y + x - 1; | |
| 113 | } else if (y <= -0.5) { | |
| 114 | y = y + x + 1; | |
| 115 | } else { | |
| 116 | y = y + x; | |
| 117 | } | |
| 118 | ||
| 119 | if (u >> 127 != 0) { | |
| 120 | return -y; | |
| 121 | } else { | |
| 122 | return y; | |
| 123 | } | |
| 124 | } | |
| 125 | ||
| 126 | test "round32" { | |
| 127 | try expect(roundf(1.3) == 1.0); | |
| 128 | try expect(roundf(-1.3) == -1.0); | |
| 129 | try expect(roundf(0.2) == 0.0); | |
| 130 | try expect(roundf(1.8) == 2.0); | |
| 131 | } | |
| 132 | ||
| 133 | test "round64" { | |
| 134 | try expect(round(1.3) == 1.0); | |
| 135 | try expect(round(-1.3) == -1.0); | |
| 136 | try expect(round(0.2) == 0.0); | |
| 137 | try expect(round(1.8) == 2.0); | |
| 138 | } | |
| 139 | ||
| 140 | test "round128" { | |
| 141 | try expect(roundq(1.3) == 1.0); | |
| 142 | try expect(roundq(-1.3) == -1.0); | |
| 143 | try expect(roundq(0.2) == 0.0); | |
| 144 | try expect(roundq(1.8) == 2.0); | |
| 145 | } | |
| 146 | ||
| 147 | test "round32.special" { | |
| 148 | try expect(roundf(0.0) == 0.0); | |
| 149 | try expect(roundf(-0.0) == -0.0); | |
| 150 | try expect(math.isPositiveInf(roundf(math.inf(f32)))); | |
| 151 | try expect(math.isNegativeInf(roundf(-math.inf(f32)))); | |
| 152 | try expect(math.isNan(roundf(math.nan(f32)))); | |
| 153 | } | |
| 154 | ||
| 155 | test "round64.special" { | |
| 156 | try expect(round(0.0) == 0.0); | |
| 157 | try expect(round(-0.0) == -0.0); | |
| 158 | try expect(math.isPositiveInf(round(math.inf(f64)))); | |
| 159 | try expect(math.isNegativeInf(round(-math.inf(f64)))); | |
| 160 | try expect(math.isNan(round(math.nan(f64)))); | |
| 161 | } | |
| 162 | ||
| 163 | test "round128.special" { | |
| 164 | try expect(roundq(0.0) == 0.0); | |
| 165 | try expect(roundq(-0.0) == -0.0); | |
| 166 | try expect(math.isPositiveInf(roundq(math.inf(f128)))); | |
| 167 | try expect(math.isNegativeInf(roundq(-math.inf(f128)))); | |
| 168 | try expect(math.isNan(roundq(math.nan(f128)))); | |
| 169 | } |
lib/std/special/compiler_rt/sin.zig created+168| ... | ... | @@ -0,0 +1,168 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/sinf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/sin.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | const kernel = @import("trig.zig"); | |
| 12 | const rem_pio2 = @import("rem_pio2.zig").rem_pio2; | |
| 13 | const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; | |
| 14 | ||
| 15 | pub fn __sinh(x: f16) callconv(.C) f16 { | |
| 16 | // TODO: more efficient implementation | |
| 17 | return @floatCast(f16, sinf(x)); | |
| 18 | } | |
| 19 | ||
| 20 | pub fn sinf(x: f32) callconv(.C) f32 { | |
| 21 | // Small multiples of pi/2 rounded to double precision. | |
| 22 | const s1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 | |
| 23 | const s2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 | |
| 24 | const s3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2 | |
| 25 | const s4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18 | |
| 26 | ||
| 27 | var ix = @bitCast(u32, x); | |
| 28 | const sign = ix >> 31 != 0; | |
| 29 | ix &= 0x7fffffff; | |
| 30 | ||
| 31 | if (ix <= 0x3f490fda) { // |x| ~<= pi/4 | |
| 32 | if (ix < 0x39800000) { // |x| < 2**-12 | |
| 33 | // raise inexact if x!=0 and underflow if subnormal | |
| 34 | math.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120); | |
| 35 | return x; | |
| 36 | } | |
| 37 | return kernel.__sindf(x); | |
| 38 | } | |
| 39 | if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4 | |
| 40 | if (ix <= 0x4016cbe3) { // |x| ~<= 3pi/4 | |
| 41 | if (sign) { | |
| 42 | return -kernel.__cosdf(x + s1pio2); | |
| 43 | } else { | |
| 44 | return kernel.__cosdf(x - s1pio2); | |
| 45 | } | |
| 46 | } | |
| 47 | return kernel.__sindf(if (sign) -(x + s2pio2) else -(x - s2pio2)); | |
| 48 | } | |
| 49 | if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4 | |
| 50 | if (ix <= 0x40afeddf) { // |x| ~<= 7*pi/4 | |
| 51 | if (sign) { | |
| 52 | return kernel.__cosdf(x + s3pio2); | |
| 53 | } else { | |
| 54 | return -kernel.__cosdf(x - s3pio2); | |
| 55 | } | |
| 56 | } | |
| 57 | return kernel.__sindf(if (sign) x + s4pio2 else x - s4pio2); | |
| 58 | } | |
| 59 | ||
| 60 | // sin(Inf or NaN) is NaN | |
| 61 | if (ix >= 0x7f800000) { | |
| 62 | return x - x; | |
| 63 | } | |
| 64 | ||
| 65 | var y: f64 = undefined; | |
| 66 | const n = rem_pio2f(x, &y); | |
| 67 | return switch (n & 3) { | |
| 68 | 0 => kernel.__sindf(y), | |
| 69 | 1 => kernel.__cosdf(y), | |
| 70 | 2 => kernel.__sindf(-y), | |
| 71 | else => -kernel.__cosdf(y), | |
| 72 | }; | |
| 73 | } | |
| 74 | ||
| 75 | pub fn sin(x: f64) callconv(.C) f64 { | |
| 76 | var ix = @bitCast(u64, x) >> 32; | |
| 77 | ix &= 0x7fffffff; | |
| 78 | ||
| 79 | // |x| ~< pi/4 | |
| 80 | if (ix <= 0x3fe921fb) { | |
| 81 | if (ix < 0x3e500000) { // |x| < 2**-26 | |
| 82 | // raise inexact if x != 0 and underflow if subnormal | |
| 83 | math.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120); | |
| 84 | return x; | |
| 85 | } | |
| 86 | return kernel.__sin(x, 0.0, 0); | |
| 87 | } | |
| 88 | ||
| 89 | // sin(Inf or NaN) is NaN | |
| 90 | if (ix >= 0x7ff00000) { | |
| 91 | return x - x; | |
| 92 | } | |
| 93 | ||
| 94 | var y: [2]f64 = undefined; | |
| 95 | const n = rem_pio2(x, &y); | |
| 96 | return switch (n & 3) { | |
| 97 | 0 => kernel.__sin(y[0], y[1], 1), | |
| 98 | 1 => kernel.__cos(y[0], y[1]), | |
| 99 | 2 => -kernel.__sin(y[0], y[1], 1), | |
| 100 | else => -kernel.__cos(y[0], y[1]), | |
| 101 | }; | |
| 102 | } | |
| 103 | ||
| 104 | pub fn __sinx(x: f80) callconv(.C) f80 { | |
| 105 | // TODO: more efficient implementation | |
| 106 | return @floatCast(f80, sinq(x)); | |
| 107 | } | |
| 108 | ||
| 109 | pub fn sinq(x: f128) callconv(.C) f128 { | |
| 110 | // TODO: more correct implementation | |
| 111 | return sin(@floatCast(f64, x)); | |
| 112 | } | |
| 113 | ||
| 114 | test "sin" { | |
| 115 | try expect(sin(@as(f32, 0.0)) == sinf(0.0)); | |
| 116 | try expect(sin(@as(f64, 0.0)) == sin(0.0)); | |
| 117 | try expect(comptime (math.sin(@as(f64, 2))) == math.sin(@as(f64, 2))); | |
| 118 | } | |
| 119 | ||
| 120 | test "sin32" { | |
| 121 | const epsilon = 0.00001; | |
| 122 | ||
| 123 | try expect(math.approxEqAbs(f32, sinf(0.0), 0.0, epsilon)); | |
| 124 | try expect(math.approxEqAbs(f32, sinf(0.2), 0.198669, epsilon)); | |
| 125 | try expect(math.approxEqAbs(f32, sinf(0.8923), 0.778517, epsilon)); | |
| 126 | try expect(math.approxEqAbs(f32, sinf(1.5), 0.997495, epsilon)); | |
| 127 | try expect(math.approxEqAbs(f32, sinf(-1.5), -0.997495, epsilon)); | |
| 128 | try expect(math.approxEqAbs(f32, sinf(37.45), -0.246544, epsilon)); | |
| 129 | try expect(math.approxEqAbs(f32, sinf(89.123), 0.916166, epsilon)); | |
| 130 | } | |
| 131 | ||
| 132 | test "sin64" { | |
| 133 | const epsilon = 0.000001; | |
| 134 | ||
| 135 | try expect(math.approxEqAbs(f64, sin(0.0), 0.0, epsilon)); | |
| 136 | try expect(math.approxEqAbs(f64, sin(0.2), 0.198669, epsilon)); | |
| 137 | try expect(math.approxEqAbs(f64, sin(0.8923), 0.778517, epsilon)); | |
| 138 | try expect(math.approxEqAbs(f64, sin(1.5), 0.997495, epsilon)); | |
| 139 | try expect(math.approxEqAbs(f64, sin(-1.5), -0.997495, epsilon)); | |
| 140 | try expect(math.approxEqAbs(f64, sin(37.45), -0.246543, epsilon)); | |
| 141 | try expect(math.approxEqAbs(f64, sin(89.123), 0.916166, epsilon)); | |
| 142 | } | |
| 143 | ||
| 144 | test "sin32.special" { | |
| 145 | try expect(sinf(0.0) == 0.0); | |
| 146 | try expect(sinf(-0.0) == -0.0); | |
| 147 | try expect(math.isNan(sinf(math.inf(f32)))); | |
| 148 | try expect(math.isNan(sinf(-math.inf(f32)))); | |
| 149 | try expect(math.isNan(sinf(math.nan(f32)))); | |
| 150 | } | |
| 151 | ||
| 152 | test "sin64.special" { | |
| 153 | try expect(sin(0.0) == 0.0); | |
| 154 | try expect(sin(-0.0) == -0.0); | |
| 155 | try expect(math.isNan(sin(math.inf(f64)))); | |
| 156 | try expect(math.isNan(sin(-math.inf(f64)))); | |
| 157 | try expect(math.isNan(sin(math.nan(f64)))); | |
| 158 | } | |
| 159 | ||
| 160 | test "sin32 #9901" { | |
| 161 | const float = @bitCast(f32, @as(u32, 0b11100011111111110000000000000000)); | |
| 162 | _ = sinf(float); | |
| 163 | } | |
| 164 | ||
| 165 | test "sin64 #9901" { | |
| 166 | const float = @bitCast(f64, @as(u64, 0b1111111101000001000000001111110111111111100000000000000000000001)); | |
| 167 | _ = sin(float); | |
| 168 | } |
lib/std/special/compiler_rt/sincos.zig created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | pub fn __sincosh(a: f16, r_sin: *f16, r_cos: *f16) callconv(.C) void { | |
| 2 | r_sin.* = @sin(a); | |
| 3 | r_cos.* = @cos(a); | |
| 4 | } | |
| 5 | ||
| 6 | pub fn sincosf(a: f32, r_sin: *f32, r_cos: *f32) callconv(.C) void { | |
| 7 | r_sin.* = @sin(a); | |
| 8 | r_cos.* = @cos(a); | |
| 9 | } | |
| 10 | ||
| 11 | pub fn sincos(a: f64, r_sin: *f64, r_cos: *f64) callconv(.C) void { | |
| 12 | r_sin.* = @sin(a); | |
| 13 | r_cos.* = @cos(a); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn __sincosx(a: f80, r_sin: *f80, r_cos: *f80) callconv(.C) void { | |
| 17 | r_sin.* = @sin(a); | |
| 18 | r_cos.* = @cos(a); | |
| 19 | } | |
| 20 | ||
| 21 | pub fn sincosq(a: f128, r_sin: *f128, r_cos: *f128) callconv(.C) void { | |
| 22 | r_sin.* = @sin(a); | |
| 23 | r_cos.* = @cos(a); | |
| 24 | } |
lib/std/special/compiler_rt/sqrt.zig created+284| ... | ... | @@ -0,0 +1,284 @@ |
| 1 | const std = @import("std"); | |
| 2 | const math = std.math; | |
| 3 | ||
| 4 | pub fn __sqrth(x: f16) callconv(.C) f16 { | |
| 5 | // TODO: more efficient implementation | |
| 6 | return @floatCast(f16, sqrtf(x)); | |
| 7 | } | |
| 8 | ||
| 9 | pub fn sqrtf(x: f32) callconv(.C) f32 { | |
| 10 | const tiny: f32 = 1.0e-30; | |
| 11 | const sign: i32 = @bitCast(i32, @as(u32, 0x80000000)); | |
| 12 | var ix: i32 = @bitCast(i32, x); | |
| 13 | ||
| 14 | if ((ix & 0x7F800000) == 0x7F800000) { | |
| 15 | return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan | |
| 16 | } | |
| 17 | ||
| 18 | // zero | |
| 19 | if (ix <= 0) { | |
| 20 | if (ix & ~sign == 0) { | |
| 21 | return x; // sqrt (+-0) = +-0 | |
| 22 | } | |
| 23 | if (ix < 0) { | |
| 24 | return math.snan(f32); | |
| 25 | } | |
| 26 | } | |
| 27 | ||
| 28 | // normalize | |
| 29 | var m = ix >> 23; | |
| 30 | if (m == 0) { | |
| 31 | // subnormal | |
| 32 | var i: i32 = 0; | |
| 33 | while (ix & 0x00800000 == 0) : (i += 1) { | |
| 34 | ix <<= 1; | |
| 35 | } | |
| 36 | m -= i - 1; | |
| 37 | } | |
| 38 | ||
| 39 | m -= 127; // unbias exponent | |
| 40 | ix = (ix & 0x007FFFFF) | 0x00800000; | |
| 41 | ||
| 42 | if (m & 1 != 0) { // odd m, double x to even | |
| 43 | ix += ix; | |
| 44 | } | |
| 45 | ||
| 46 | m >>= 1; // m = [m / 2] | |
| 47 | ||
| 48 | // sqrt(x) bit by bit | |
| 49 | ix += ix; | |
| 50 | var q: i32 = 0; // q = sqrt(x) | |
| 51 | var s: i32 = 0; | |
| 52 | var r: i32 = 0x01000000; // r = moving bit right -> left | |
| 53 | ||
| 54 | while (r != 0) { | |
| 55 | const t = s + r; | |
| 56 | if (t <= ix) { | |
| 57 | s = t + r; | |
| 58 | ix -= t; | |
| 59 | q += r; | |
| 60 | } | |
| 61 | ix += ix; | |
| 62 | r >>= 1; | |
| 63 | } | |
| 64 | ||
| 65 | // floating add to find rounding direction | |
| 66 | if (ix != 0) { | |
| 67 | var z = 1.0 - tiny; // inexact | |
| 68 | if (z >= 1.0) { | |
| 69 | z = 1.0 + tiny; | |
| 70 | if (z > 1.0) { | |
| 71 | q += 2; | |
| 72 | } else { | |
| 73 | if (q & 1 != 0) { | |
| 74 | q += 1; | |
| 75 | } | |
| 76 | } | |
| 77 | } | |
| 78 | } | |
| 79 | ||
| 80 | ix = (q >> 1) + 0x3f000000; | |
| 81 | ix += m << 23; | |
| 82 | return @bitCast(f32, ix); | |
| 83 | } | |
| 84 | ||
| 85 | /// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound | |
| 86 | /// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are | |
| 87 | /// potentially some edge cases remaining that are not handled in the same way. | |
| 88 | pub fn sqrt(x: f64) callconv(.C) f64 { | |
| 89 | const tiny: f64 = 1.0e-300; | |
| 90 | const sign: u32 = 0x80000000; | |
| 91 | const u = @bitCast(u64, x); | |
| 92 | ||
| 93 | var ix0 = @intCast(u32, u >> 32); | |
| 94 | var ix1 = @intCast(u32, u & 0xFFFFFFFF); | |
| 95 | ||
| 96 | // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan | |
| 97 | if (ix0 & 0x7FF00000 == 0x7FF00000) { | |
| 98 | return x * x + x; | |
| 99 | } | |
| 100 | ||
| 101 | // sqrt(+-0) = +-0 | |
| 102 | if (x == 0.0) { | |
| 103 | return x; | |
| 104 | } | |
| 105 | // sqrt(-ve) = snan | |
| 106 | if (ix0 & sign != 0) { | |
| 107 | return math.snan(f64); | |
| 108 | } | |
| 109 | ||
| 110 | // normalize x | |
| 111 | var m = @intCast(i32, ix0 >> 20); | |
| 112 | if (m == 0) { | |
| 113 | // subnormal | |
| 114 | while (ix0 == 0) { | |
| 115 | m -= 21; | |
| 116 | ix0 |= ix1 >> 11; | |
| 117 | ix1 <<= 21; | |
| 118 | } | |
| 119 | ||
| 120 | // subnormal | |
| 121 | var i: u32 = 0; | |
| 122 | while (ix0 & 0x00100000 == 0) : (i += 1) { | |
| 123 | ix0 <<= 1; | |
| 124 | } | |
| 125 | m -= @intCast(i32, i) - 1; | |
| 126 | ix0 |= ix1 >> @intCast(u5, 32 - i); | |
| 127 | ix1 <<= @intCast(u5, i); | |
| 128 | } | |
| 129 | ||
| 130 | // unbias exponent | |
| 131 | m -= 1023; | |
| 132 | ix0 = (ix0 & 0x000FFFFF) | 0x00100000; | |
| 133 | if (m & 1 != 0) { | |
| 134 | ix0 += ix0 + (ix1 >> 31); | |
| 135 | ix1 = ix1 +% ix1; | |
| 136 | } | |
| 137 | m >>= 1; | |
| 138 | ||
| 139 | // sqrt(x) bit by bit | |
| 140 | ix0 += ix0 + (ix1 >> 31); | |
| 141 | ix1 = ix1 +% ix1; | |
| 142 | ||
| 143 | var q: u32 = 0; | |
| 144 | var q1: u32 = 0; | |
| 145 | var s0: u32 = 0; | |
| 146 | var s1: u32 = 0; | |
| 147 | var r: u32 = 0x00200000; | |
| 148 | var t: u32 = undefined; | |
| 149 | var t1: u32 = undefined; | |
| 150 | ||
| 151 | while (r != 0) { | |
| 152 | t = s0 +% r; | |
| 153 | if (t <= ix0) { | |
| 154 | s0 = t + r; | |
| 155 | ix0 -= t; | |
| 156 | q += r; | |
| 157 | } | |
| 158 | ix0 = ix0 +% ix0 +% (ix1 >> 31); | |
| 159 | ix1 = ix1 +% ix1; | |
| 160 | r >>= 1; | |
| 161 | } | |
| 162 | ||
| 163 | r = sign; | |
| 164 | while (r != 0) { | |
| 165 | t1 = s1 +% r; | |
| 166 | t = s0; | |
| 167 | if (t < ix0 or (t == ix0 and t1 <= ix1)) { | |
| 168 | s1 = t1 +% r; | |
| 169 | if (t1 & sign == sign and s1 & sign == 0) { | |
| 170 | s0 += 1; | |
| 171 | } | |
| 172 | ix0 -= t; | |
| 173 | if (ix1 < t1) { | |
| 174 | ix0 -= 1; | |
| 175 | } | |
| 176 | ix1 = ix1 -% t1; | |
| 177 | q1 += r; | |
| 178 | } | |
| 179 | ix0 = ix0 +% ix0 +% (ix1 >> 31); | |
| 180 | ix1 = ix1 +% ix1; | |
| 181 | r >>= 1; | |
| 182 | } | |
| 183 | ||
| 184 | // rounding direction | |
| 185 | if (ix0 | ix1 != 0) { | |
| 186 | var z = 1.0 - tiny; // raise inexact | |
| 187 | if (z >= 1.0) { | |
| 188 | z = 1.0 + tiny; | |
| 189 | if (q1 == 0xFFFFFFFF) { | |
| 190 | q1 = 0; | |
| 191 | q += 1; | |
| 192 | } else if (z > 1.0) { | |
| 193 | if (q1 == 0xFFFFFFFE) { | |
| 194 | q += 1; | |
| 195 | } | |
| 196 | q1 += 2; | |
| 197 | } else { | |
| 198 | q1 += q1 & 1; | |
| 199 | } | |
| 200 | } | |
| 201 | } | |
| 202 | ||
| 203 | ix0 = (q >> 1) + 0x3FE00000; | |
| 204 | ix1 = q1 >> 1; | |
| 205 | if (q & 1 != 0) { | |
| 206 | ix1 |= 0x80000000; | |
| 207 | } | |
| 208 | ||
| 209 | // NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same | |
| 210 | // behaviour at least. | |
| 211 | var iix0 = @intCast(i32, ix0); | |
| 212 | iix0 = iix0 +% (m << 20); | |
| 213 | ||
| 214 | const uz = (@intCast(u64, iix0) << 32) | ix1; | |
| 215 | return @bitCast(f64, uz); | |
| 216 | } | |
| 217 | ||
| 218 | pub fn __sqrtx(x: f80) callconv(.C) f80 { | |
| 219 | // TODO: more efficient implementation | |
| 220 | return @floatCast(f80, sqrtq(x)); | |
| 221 | } | |
| 222 | ||
| 223 | pub fn sqrtq(x: f128) callconv(.C) f128 { | |
| 224 | // TODO: more correct implementation | |
| 225 | return sqrt(@floatCast(f64, x)); | |
| 226 | } | |
| 227 | ||
| 228 | test "sqrtf" { | |
| 229 | const V = [_]f32{ | |
| 230 | 0.0, | |
| 231 | 4.089288054930154, | |
| 232 | 7.538757127071935, | |
| 233 | 8.97780793672623, | |
| 234 | 5.304443821913729, | |
| 235 | 5.682408965311888, | |
| 236 | 0.5846878579110049, | |
| 237 | 3.650338664297043, | |
| 238 | 0.3178091951800732, | |
| 239 | 7.1505232436382835, | |
| 240 | 3.6589165881946464, | |
| 241 | }; | |
| 242 | ||
| 243 | // Note that @sqrt will either generate the sqrt opcode (if supported by the | |
| 244 | // target ISA) or a call to `sqrtf` otherwise. | |
| 245 | for (V) |val| | |
| 246 | try std.testing.expectEqual(@sqrt(val), sqrtf(val)); | |
| 247 | } | |
| 248 | ||
| 249 | test "sqrtf special" { | |
| 250 | try std.testing.expect(math.isPositiveInf(sqrtf(math.inf(f32)))); | |
| 251 | try std.testing.expect(sqrtf(0.0) == 0.0); | |
| 252 | try std.testing.expect(sqrtf(-0.0) == -0.0); | |
| 253 | try std.testing.expect(math.isNan(sqrtf(-1.0))); | |
| 254 | try std.testing.expect(math.isNan(sqrtf(math.nan(f32)))); | |
| 255 | } | |
| 256 | ||
| 257 | test "sqrt" { | |
| 258 | const V = [_]f64{ | |
| 259 | 0.0, | |
| 260 | 4.089288054930154, | |
| 261 | 7.538757127071935, | |
| 262 | 8.97780793672623, | |
| 263 | 5.304443821913729, | |
| 264 | 5.682408965311888, | |
| 265 | 0.5846878579110049, | |
| 266 | 3.650338664297043, | |
| 267 | 0.3178091951800732, | |
| 268 | 7.1505232436382835, | |
| 269 | 3.6589165881946464, | |
| 270 | }; | |
| 271 | ||
| 272 | // Note that @sqrt will either generate the sqrt opcode (if supported by the | |
| 273 | // target ISA) or a call to `sqrtf` otherwise. | |
| 274 | for (V) |val| | |
| 275 | try std.testing.expectEqual(@sqrt(val), sqrt(val)); | |
| 276 | } | |
| 277 | ||
| 278 | test "sqrt special" { | |
| 279 | try std.testing.expect(math.isPositiveInf(sqrt(math.inf(f64)))); | |
| 280 | try std.testing.expect(sqrt(0.0) == 0.0); | |
| 281 | try std.testing.expect(sqrt(-0.0) == -0.0); | |
| 282 | try std.testing.expect(math.isNan(sqrt(-1.0))); | |
| 283 | try std.testing.expect(math.isNan(sqrt(math.nan(f64)))); | |
| 284 | } |
lib/std/special/compiler_rt/tan.zig created+140| ... | ... | @@ -0,0 +1,140 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/tanf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/tan.c | |
| 6 | // https://golang.org/src/math/tan.go | |
| 7 | ||
| 8 | const std = @import("std"); | |
| 9 | const math = std.math; | |
| 10 | const expect = std.testing.expect; | |
| 11 | ||
| 12 | const kernel = @import("trig.zig"); | |
| 13 | const rem_pio2 = @import("rem_pio2.zig").rem_pio2; | |
| 14 | const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; | |
| 15 | ||
| 16 | pub fn __tanh(x: f16) callconv(.C) f16 { | |
| 17 | // TODO: more efficient implementation | |
| 18 | return @floatCast(f16, tanf(x)); | |
| 19 | } | |
| 20 | ||
| 21 | pub fn tanf(x: f32) callconv(.C) f32 { | |
| 22 | // Small multiples of pi/2 rounded to double precision. | |
| 23 | const t1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 | |
| 24 | const t2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 | |
| 25 | const t3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2 | |
| 26 | const t4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18 | |
| 27 | ||
| 28 | var ix = @bitCast(u32, x); | |
| 29 | const sign = ix >> 31 != 0; | |
| 30 | ix &= 0x7fffffff; | |
| 31 | ||
| 32 | if (ix <= 0x3f490fda) { // |x| ~<= pi/4 | |
| 33 | if (ix < 0x39800000) { // |x| < 2**-12 | |
| 34 | // raise inexact if x!=0 and underflow if subnormal | |
| 35 | math.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120); | |
| 36 | return x; | |
| 37 | } | |
| 38 | return kernel.__tandf(x, false); | |
| 39 | } | |
| 40 | if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4 | |
| 41 | if (ix <= 0x4016cbe3) { // |x| ~<= 3pi/4 | |
| 42 | return kernel.__tandf((if (sign) x + t1pio2 else x - t1pio2), true); | |
| 43 | } else { | |
| 44 | return kernel.__tandf((if (sign) x + t2pio2 else x - t2pio2), false); | |
| 45 | } | |
| 46 | } | |
| 47 | if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4 | |
| 48 | if (ix <= 0x40afeddf) { // |x| ~<= 7*pi/4 | |
| 49 | return kernel.__tandf((if (sign) x + t3pio2 else x - t3pio2), true); | |
| 50 | } else { | |
| 51 | return kernel.__tandf((if (sign) x + t4pio2 else x - t4pio2), false); | |
| 52 | } | |
| 53 | } | |
| 54 | ||
| 55 | // tan(Inf or NaN) is NaN | |
| 56 | if (ix >= 0x7f800000) { | |
| 57 | return x - x; | |
| 58 | } | |
| 59 | ||
| 60 | var y: f64 = undefined; | |
| 61 | const n = rem_pio2f(x, &y); | |
| 62 | return kernel.__tandf(y, n & 1 != 0); | |
| 63 | } | |
| 64 | ||
| 65 | pub fn tan(x: f64) callconv(.C) f64 { | |
| 66 | var ix = @bitCast(u64, x) >> 32; | |
| 67 | ix &= 0x7fffffff; | |
| 68 | ||
| 69 | // |x| ~< pi/4 | |
| 70 | if (ix <= 0x3fe921fb) { | |
| 71 | if (ix < 0x3e400000) { // |x| < 2**-27 | |
| 72 | // raise inexact if x!=0 and underflow if subnormal | |
| 73 | math.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120); | |
| 74 | return x; | |
| 75 | } | |
| 76 | return kernel.__tan(x, 0.0, false); | |
| 77 | } | |
| 78 | ||
| 79 | // tan(Inf or NaN) is NaN | |
| 80 | if (ix >= 0x7ff00000) { | |
| 81 | return x - x; | |
| 82 | } | |
| 83 | ||
| 84 | var y: [2]f64 = undefined; | |
| 85 | const n = rem_pio2(x, &y); | |
| 86 | return kernel.__tan(y[0], y[1], n & 1 != 0); | |
| 87 | } | |
| 88 | ||
| 89 | pub fn __tanx(x: f80) callconv(.C) f80 { | |
| 90 | // TODO: more efficient implementation | |
| 91 | return @floatCast(f80, tanq(x)); | |
| 92 | } | |
| 93 | ||
| 94 | pub fn tanq(x: f128) callconv(.C) f128 { | |
| 95 | // TODO: more correct implementation | |
| 96 | return tan(@floatCast(f64, x)); | |
| 97 | } | |
| 98 | ||
| 99 | test "tan" { | |
| 100 | try expect(tan(@as(f32, 0.0)) == tanf(0.0)); | |
| 101 | try expect(tan(@as(f64, 0.0)) == tan(0.0)); | |
| 102 | } | |
| 103 | ||
| 104 | test "tan32" { | |
| 105 | const epsilon = 0.00001; | |
| 106 | ||
| 107 | try expect(math.approxEqAbs(f32, tanf(0.0), 0.0, epsilon)); | |
| 108 | try expect(math.approxEqAbs(f32, tanf(0.2), 0.202710, epsilon)); | |
| 109 | try expect(math.approxEqAbs(f32, tanf(0.8923), 1.240422, epsilon)); | |
| 110 | try expect(math.approxEqAbs(f32, tanf(1.5), 14.101420, epsilon)); | |
| 111 | try expect(math.approxEqAbs(f32, tanf(37.45), -0.254397, epsilon)); | |
| 112 | try expect(math.approxEqAbs(f32, tanf(89.123), 2.285852, epsilon)); | |
| 113 | } | |
| 114 | ||
| 115 | test "tan64" { | |
| 116 | const epsilon = 0.000001; | |
| 117 | ||
| 118 | try expect(math.approxEqAbs(f64, tan(0.0), 0.0, epsilon)); | |
| 119 | try expect(math.approxEqAbs(f64, tan(0.2), 0.202710, epsilon)); | |
| 120 | try expect(math.approxEqAbs(f64, tan(0.8923), 1.240422, epsilon)); | |
| 121 | try expect(math.approxEqAbs(f64, tan(1.5), 14.101420, epsilon)); | |
| 122 | try expect(math.approxEqAbs(f64, tan(37.45), -0.254397, epsilon)); | |
| 123 | try expect(math.approxEqAbs(f64, tan(89.123), 2.2858376, epsilon)); | |
| 124 | } | |
| 125 | ||
| 126 | test "tan32.special" { | |
| 127 | try expect(tanf(0.0) == 0.0); | |
| 128 | try expect(tanf(-0.0) == -0.0); | |
| 129 | try expect(math.isNan(tanf(math.inf(f32)))); | |
| 130 | try expect(math.isNan(tanf(-math.inf(f32)))); | |
| 131 | try expect(math.isNan(tanf(math.nan(f32)))); | |
| 132 | } | |
| 133 | ||
| 134 | test "tan64.special" { | |
| 135 | try expect(tan(0.0) == 0.0); | |
| 136 | try expect(tan(-0.0) == -0.0); | |
| 137 | try expect(math.isNan(tan(math.inf(f64)))); | |
| 138 | try expect(math.isNan(tan(-math.inf(f64)))); | |
| 139 | try expect(math.isNan(tan(math.nan(f64)))); | |
| 140 | } |
lib/std/special/compiler_rt/trig.zig created+273| ... | ... | @@ -0,0 +1,273 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__cos.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__cosdf.c | |
| 6 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__sin.c | |
| 7 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__sindf.c | |
| 8 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__tand.c | |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/__tandf.c | |
| 10 | ||
| 11 | /// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 | |
| 12 | /// Input x is assumed to be bounded by ~pi/4 in magnitude. | |
| 13 | /// Input y is the tail of x. | |
| 14 | /// | |
| 15 | /// Algorithm | |
| 16 | /// 1. Since cos(-x) = cos(x), we need only to consider positive x. | |
| 17 | /// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. | |
| 18 | /// 3. cos(x) is approximated by a polynomial of degree 14 on | |
| 19 | /// [0,pi/4] | |
| 20 | /// 4 14 | |
| 21 | /// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x | |
| 22 | /// where the remez error is | |
| 23 | /// | |
| 24 | /// | 2 4 6 8 10 12 14 | -58 | |
| 25 | /// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 | |
| 26 | /// | | | |
| 27 | /// | |
| 28 | /// 4 6 8 10 12 14 | |
| 29 | /// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then | |
| 30 | /// cos(x) ~ 1 - x*x/2 + r | |
| 31 | /// since cos(x+y) ~ cos(x) - sin(x)*y | |
| 32 | /// ~ cos(x) - x*y, | |
| 33 | /// a correction term is necessary in cos(x) and hence | |
| 34 | /// cos(x+y) = 1 - (x*x/2 - (r - x*y)) | |
| 35 | /// For better accuracy, rearrange to | |
| 36 | /// cos(x+y) ~ w + (tmp + (r-x*y)) | |
| 37 | /// where w = 1 - x*x/2 and tmp is a tiny correction term | |
| 38 | /// (1 - x*x/2 == w + tmp exactly in infinite precision). | |
| 39 | /// The exactness of w + tmp in infinite precision depends on w | |
| 40 | /// and tmp having the same precision as x. If they have extra | |
| 41 | /// precision due to compiler bugs, then the extra precision is | |
| 42 | /// only good provided it is retained in all terms of the final | |
| 43 | /// expression for cos(). Retention happens in all cases tested | |
| 44 | /// under FreeBSD, so don't pessimize things by forcibly clipping | |
| 45 | /// any extra precision in w. | |
| 46 | pub fn __cos(x: f64, y: f64) f64 { | |
| 47 | const C1 = 4.16666666666666019037e-02; // 0x3FA55555, 0x5555554C | |
| 48 | const C2 = -1.38888888888741095749e-03; // 0xBF56C16C, 0x16C15177 | |
| 49 | const C3 = 2.48015872894767294178e-05; // 0x3EFA01A0, 0x19CB1590 | |
| 50 | const C4 = -2.75573143513906633035e-07; // 0xBE927E4F, 0x809C52AD | |
| 51 | const C5 = 2.08757232129817482790e-09; // 0x3E21EE9E, 0xBDB4B1C4 | |
| 52 | const C6 = -1.13596475577881948265e-11; // 0xBDA8FAE9, 0xBE8838D4 | |
| 53 | ||
| 54 | const z = x * x; | |
| 55 | const zs = z * z; | |
| 56 | const r = z * (C1 + z * (C2 + z * C3)) + zs * zs * (C4 + z * (C5 + z * C6)); | |
| 57 | const hz = 0.5 * z; | |
| 58 | const w = 1.0 - hz; | |
| 59 | return w + (((1.0 - w) - hz) + (z * r - x * y)); | |
| 60 | } | |
| 61 | ||
| 62 | pub fn __cosdf(x: f64) f32 { | |
| 63 | // |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). | |
| 64 | const C0 = -0x1ffffffd0c5e81.0p-54; // -0.499999997251031003120 | |
| 65 | const C1 = 0x155553e1053a42.0p-57; // 0.0416666233237390631894 | |
| 66 | const C2 = -0x16c087e80f1e27.0p-62; // -0.00138867637746099294692 | |
| 67 | const C3 = 0x199342e0ee5069.0p-68; // 0.0000243904487962774090654 | |
| 68 | ||
| 69 | // Try to optimize for parallel evaluation as in __tandf.c. | |
| 70 | const z = x * x; | |
| 71 | const w = z * z; | |
| 72 | const r = C2 + z * C3; | |
| 73 | return @floatCast(f32, ((1.0 + z * C0) + w * C1) + (w * z) * r); | |
| 74 | } | |
| 75 | ||
| 76 | /// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 | |
| 77 | /// Input x is assumed to be bounded by ~pi/4 in magnitude. | |
| 78 | /// Input y is the tail of x. | |
| 79 | /// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). | |
| 80 | /// | |
| 81 | /// Algorithm | |
| 82 | /// 1. Since sin(-x) = -sin(x), we need only to consider positive x. | |
| 83 | /// 2. Callers must return sin(-0) = -0 without calling here since our | |
| 84 | /// odd polynomial is not evaluated in a way that preserves -0. | |
| 85 | /// Callers may do the optimization sin(x) ~ x for tiny x. | |
| 86 | /// 3. sin(x) is approximated by a polynomial of degree 13 on | |
| 87 | /// [0,pi/4] | |
| 88 | /// 3 13 | |
| 89 | /// sin(x) ~ x + S1*x + ... + S6*x | |
| 90 | /// where | |
| 91 | /// | |
| 92 | /// |sin(x) 2 4 6 8 10 12 | -58 | |
| 93 | /// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 | |
| 94 | /// | x | | |
| 95 | /// | |
| 96 | /// 4. sin(x+y) = sin(x) + sin'(x')*y | |
| 97 | /// ~ sin(x) + (1-x*x/2)*y | |
| 98 | /// For better accuracy, let | |
| 99 | /// 3 2 2 2 2 | |
| 100 | /// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) | |
| 101 | /// then 3 2 | |
| 102 | /// sin(x) = x + (S1*x + (x *(r-y/2)+y)) | |
| 103 | pub fn __sin(x: f64, y: f64, iy: i32) f64 { | |
| 104 | const S1 = -1.66666666666666324348e-01; // 0xBFC55555, 0x55555549 | |
| 105 | const S2 = 8.33333333332248946124e-03; // 0x3F811111, 0x1110F8A6 | |
| 106 | const S3 = -1.98412698298579493134e-04; // 0xBF2A01A0, 0x19C161D5 | |
| 107 | const S4 = 2.75573137070700676789e-06; // 0x3EC71DE3, 0x57B1FE7D | |
| 108 | const S5 = -2.50507602534068634195e-08; // 0xBE5AE5E6, 0x8A2B9CEB | |
| 109 | const S6 = 1.58969099521155010221e-10; // 0x3DE5D93A, 0x5ACFD57C | |
| 110 | ||
| 111 | const z = x * x; | |
| 112 | const w = z * z; | |
| 113 | const r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); | |
| 114 | const v = z * x; | |
| 115 | if (iy == 0) { | |
| 116 | return x + v * (S1 + z * r); | |
| 117 | } else { | |
| 118 | return x - ((z * (0.5 * y - v * r) - y) - v * S1); | |
| 119 | } | |
| 120 | } | |
| 121 | ||
| 122 | pub fn __sindf(x: f64) f32 { | |
| 123 | // |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). | |
| 124 | const S1 = -0x15555554cbac77.0p-55; // -0.166666666416265235595 | |
| 125 | const S2 = 0x111110896efbb2.0p-59; // 0.0083333293858894631756 | |
| 126 | const S3 = -0x1a00f9e2cae774.0p-65; // -0.000198393348360966317347 | |
| 127 | const S4 = 0x16cd878c3b46a7.0p-71; // 0.0000027183114939898219064 | |
| 128 | ||
| 129 | // Try to optimize for parallel evaluation as in __tandf.c. | |
| 130 | const z = x * x; | |
| 131 | const w = z * z; | |
| 132 | const r = S3 + z * S4; | |
| 133 | const s = z * x; | |
| 134 | return @floatCast(f32, (x + s * (S1 + z * S2)) + s * w * r); | |
| 135 | } | |
| 136 | ||
| 137 | /// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 | |
| 138 | /// Input x is assumed to be bounded by ~pi/4 in magnitude. | |
| 139 | /// Input y is the tail of x. | |
| 140 | /// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. | |
| 141 | /// | |
| 142 | /// Algorithm | |
| 143 | /// 1. Since tan(-x) = -tan(x), we need only to consider positive x. | |
| 144 | /// 2. Callers must return tan(-0) = -0 without calling here since our | |
| 145 | /// odd polynomial is not evaluated in a way that preserves -0. | |
| 146 | /// Callers may do the optimization tan(x) ~ x for tiny x. | |
| 147 | /// 3. tan(x) is approximated by a odd polynomial of degree 27 on | |
| 148 | /// [0,0.67434] | |
| 149 | /// 3 27 | |
| 150 | /// tan(x) ~ x + T1*x + ... + T13*x | |
| 151 | /// where | |
| 152 | /// | |
| 153 | /// |tan(x) 2 4 26 | -59.2 | |
| 154 | /// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 | |
| 155 | /// | x | | |
| 156 | /// | |
| 157 | /// Note: tan(x+y) = tan(x) + tan'(x)*y | |
| 158 | /// ~ tan(x) + (1+x*x)*y | |
| 159 | /// Therefore, for better accuracy in computing tan(x+y), let | |
| 160 | /// 3 2 2 2 2 | |
| 161 | /// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) | |
| 162 | /// then | |
| 163 | /// 3 2 | |
| 164 | /// tan(x+y) = x + (T1*x + (x *(r+y)+y)) | |
| 165 | /// | |
| 166 | /// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then | |
| 167 | /// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) | |
| 168 | /// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) | |
| 169 | pub fn __tan(x_: f64, y_: f64, odd: bool) f64 { | |
| 170 | var x = x_; | |
| 171 | var y = y_; | |
| 172 | ||
| 173 | const T = [_]f64{ | |
| 174 | 3.33333333333334091986e-01, // 3FD55555, 55555563 | |
| 175 | 1.33333333333201242699e-01, // 3FC11111, 1110FE7A | |
| 176 | 5.39682539762260521377e-02, // 3FABA1BA, 1BB341FE | |
| 177 | 2.18694882948595424599e-02, // 3F9664F4, 8406D637 | |
| 178 | 8.86323982359930005737e-03, // 3F8226E3, E96E8493 | |
| 179 | 3.59207910759131235356e-03, // 3F6D6D22, C9560328 | |
| 180 | 1.45620945432529025516e-03, // 3F57DBC8, FEE08315 | |
| 181 | 5.88041240820264096874e-04, // 3F4344D8, F2F26501 | |
| 182 | 2.46463134818469906812e-04, // 3F3026F7, 1A8D1068 | |
| 183 | 7.81794442939557092300e-05, // 3F147E88, A03792A6 | |
| 184 | 7.14072491382608190305e-05, // 3F12B80F, 32F0A7E9 | |
| 185 | -1.85586374855275456654e-05, // BEF375CB, DB605373 | |
| 186 | 2.59073051863633712884e-05, // 3EFB2A70, 74BF7AD4 | |
| 187 | }; | |
| 188 | const pio4 = 7.85398163397448278999e-01; // 3FE921FB, 54442D18 | |
| 189 | const pio4lo = 3.06161699786838301793e-17; // 3C81A626, 33145C07 | |
| 190 | ||
| 191 | var z: f64 = undefined; | |
| 192 | var r: f64 = undefined; | |
| 193 | var v: f64 = undefined; | |
| 194 | var w: f64 = undefined; | |
| 195 | var s: f64 = undefined; | |
| 196 | var a: f64 = undefined; | |
| 197 | var w0: f64 = undefined; | |
| 198 | var a0: f64 = undefined; | |
| 199 | var hx: u32 = undefined; | |
| 200 | var sign: bool = undefined; | |
| 201 | ||
| 202 | hx = @intCast(u32, @bitCast(u64, x) >> 32); | |
| 203 | const big = (hx & 0x7fffffff) >= 0x3FE59428; // |x| >= 0.6744 | |
| 204 | if (big) { | |
| 205 | sign = hx >> 31 != 0; | |
| 206 | if (sign) { | |
| 207 | x = -x; | |
| 208 | y = -y; | |
| 209 | } | |
| 210 | x = (pio4 - x) + (pio4lo - y); | |
| 211 | y = 0.0; | |
| 212 | } | |
| 213 | z = x * x; | |
| 214 | w = z * z; | |
| 215 | ||
| 216 | // Break x^5*(T[1]+x^2*T[2]+...) into | |
| 217 | // x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + | |
| 218 | // x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) | |
| 219 | r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); | |
| 220 | v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); | |
| 221 | s = z * x; | |
| 222 | r = y + z * (s * (r + v) + y) + s * T[0]; | |
| 223 | w = x + r; | |
| 224 | if (big) { | |
| 225 | s = 1 - 2 * @intToFloat(f64, @boolToInt(odd)); | |
| 226 | v = s - 2.0 * (x + (r - w * w / (w + s))); | |
| 227 | return if (sign) -v else v; | |
| 228 | } | |
| 229 | if (!odd) { | |
| 230 | return w; | |
| 231 | } | |
| 232 | // -1.0/(x+r) has up to 2ulp error, so compute it accurately | |
| 233 | w0 = w; | |
| 234 | w0 = @bitCast(f64, @bitCast(u64, w0) & 0xffffffff00000000); | |
| 235 | v = r - (w0 - x); // w0+v = r+x | |
| 236 | a = -1.0 / w; | |
| 237 | a0 = a; | |
| 238 | a0 = @bitCast(f64, @bitCast(u64, a0) & 0xffffffff00000000); | |
| 239 | return a0 + a * (1.0 + a0 * w0 + a0 * v); | |
| 240 | } | |
| 241 | ||
| 242 | pub fn __tandf(x: f64, odd: bool) f32 { | |
| 243 | // |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). | |
| 244 | const T = [_]f64{ | |
| 245 | 0x15554d3418c99f.0p-54, // 0.333331395030791399758 | |
| 246 | 0x1112fd38999f72.0p-55, // 0.133392002712976742718 | |
| 247 | 0x1b54c91d865afe.0p-57, // 0.0533812378445670393523 | |
| 248 | 0x191df3908c33ce.0p-58, // 0.0245283181166547278873 | |
| 249 | 0x185dadfcecf44e.0p-61, // 0.00297435743359967304927 | |
| 250 | 0x1362b9bf971bcd.0p-59, // 0.00946564784943673166728 | |
| 251 | }; | |
| 252 | ||
| 253 | const z = x * x; | |
| 254 | // Split up the polynomial into small independent terms to give | |
| 255 | // opportunities for parallel evaluation. The chosen splitting is | |
| 256 | // micro-optimized for Athlons (XP, X64). It costs 2 multiplications | |
| 257 | // relative to Horner's method on sequential machines. | |
| 258 | // | |
| 259 | // We add the small terms from lowest degree up for efficiency on | |
| 260 | // non-sequential machines (the lowest degree terms tend to be ready | |
| 261 | // earlier). Apart from this, we don't care about order of | |
| 262 | // operations, and don't need to to care since we have precision to | |
| 263 | // spare. However, the chosen splitting is good for accuracy too, | |
| 264 | // and would give results as accurate as Horner's method if the | |
| 265 | // small terms were added from highest degree down. | |
| 266 | const r = T[4] + z * T[5]; | |
| 267 | const t = T[2] + z * T[3]; | |
| 268 | const w = z * z; | |
| 269 | const s = z * x; | |
| 270 | const u = T[0] + z * T[1]; | |
| 271 | const r0 = (x + s * u) + (s * w) * (t + w * r); | |
| 272 | return @floatCast(f32, if (odd) -1.0 / r0 else r0); | |
| 273 | } |
lib/std/special/compiler_rt/trunc.zig created+124| ... | ... | @@ -0,0 +1,124 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | |
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | |
| 3 | // | |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/truncf.c | |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const math = std.math; | |
| 9 | const expect = std.testing.expect; | |
| 10 | ||
| 11 | pub fn __trunch(x: f16) callconv(.C) f16 { | |
| 12 | // TODO: more efficient implementation | |
| 13 | return @floatCast(f16, truncf(x)); | |
| 14 | } | |
| 15 | ||
| 16 | pub fn truncf(x: f32) callconv(.C) f32 { | |
| 17 | const u = @bitCast(u32, x); | |
| 18 | var e = @intCast(i32, ((u >> 23) & 0xFF)) - 0x7F + 9; | |
| 19 | var m: u32 = undefined; | |
| 20 | ||
| 21 | if (e >= 23 + 9) { | |
| 22 | return x; | |
| 23 | } | |
| 24 | if (e < 9) { | |
| 25 | e = 1; | |
| 26 | } | |
| 27 | ||
| 28 | m = @as(u32, math.maxInt(u32)) >> @intCast(u5, e); | |
| 29 | if (u & m == 0) { | |
| 30 | return x; | |
| 31 | } else { | |
| 32 | math.doNotOptimizeAway(x + 0x1p120); | |
| 33 | return @bitCast(f32, u & ~m); | |
| 34 | } | |
| 35 | } | |
| 36 | ||
| 37 | pub fn trunc(x: f64) callconv(.C) f64 { | |
| 38 | const u = @bitCast(u64, x); | |
| 39 | var e = @intCast(i32, ((u >> 52) & 0x7FF)) - 0x3FF + 12; | |
| 40 | var m: u64 = undefined; | |
| 41 | ||
| 42 | if (e >= 52 + 12) { | |
| 43 | return x; | |
| 44 | } | |
| 45 | if (e < 12) { | |
| 46 | e = 1; | |
| 47 | } | |
| 48 | ||
| 49 | m = @as(u64, math.maxInt(u64)) >> @intCast(u6, e); | |
| 50 | if (u & m == 0) { | |
| 51 | return x; | |
| 52 | } else { | |
| 53 | math.doNotOptimizeAway(x + 0x1p120); | |
| 54 | return @bitCast(f64, u & ~m); | |
| 55 | } | |
| 56 | } | |
| 57 | ||
| 58 | pub fn __truncx(x: f80) callconv(.C) f80 { | |
| 59 | // TODO: more efficient implementation | |
| 60 | return @floatCast(f80, truncq(x)); | |
| 61 | } | |
| 62 | ||
| 63 | pub fn truncq(x: f128) callconv(.C) f128 { | |
| 64 | const u = @bitCast(u128, x); | |
| 65 | var e = @intCast(i32, ((u >> 112) & 0x7FFF)) - 0x3FFF + 16; | |
| 66 | var m: u128 = undefined; | |
| 67 | ||
| 68 | if (e >= 112 + 16) { | |
| 69 | return x; | |
| 70 | } | |
| 71 | if (e < 16) { | |
| 72 | e = 1; | |
| 73 | } | |
| 74 | ||
| 75 | m = @as(u128, math.maxInt(u128)) >> @intCast(u7, e); | |
| 76 | if (u & m == 0) { | |
| 77 | return x; | |
| 78 | } else { | |
| 79 | math.doNotOptimizeAway(x + 0x1p120); | |
| 80 | return @bitCast(f128, u & ~m); | |
| 81 | } | |
| 82 | } | |
| 83 | ||
| 84 | test "trunc32" { | |
| 85 | try expect(truncf(1.3) == 1.0); | |
| 86 | try expect(truncf(-1.3) == -1.0); | |
| 87 | try expect(truncf(0.2) == 0.0); | |
| 88 | } | |
| 89 | ||
| 90 | test "trunc64" { | |
| 91 | try expect(trunc(1.3) == 1.0); | |
| 92 | try expect(trunc(-1.3) == -1.0); | |
| 93 | try expect(trunc(0.2) == 0.0); | |
| 94 | } | |
| 95 | ||
| 96 | test "trunc128" { | |
| 97 | try expect(truncq(1.3) == 1.0); | |
| 98 | try expect(truncq(-1.3) == -1.0); | |
| 99 | try expect(truncq(0.2) == 0.0); | |
| 100 | } | |
| 101 | ||
| 102 | test "trunc32.special" { | |
| 103 | try expect(truncf(0.0) == 0.0); // 0x3F800000 | |
| 104 | try expect(truncf(-0.0) == -0.0); | |
| 105 | try expect(math.isPositiveInf(truncf(math.inf(f32)))); | |
| 106 | try expect(math.isNegativeInf(truncf(-math.inf(f32)))); | |
| 107 | try expect(math.isNan(truncf(math.nan(f32)))); | |
| 108 | } | |
| 109 | ||
| 110 | test "trunc64.special" { | |
| 111 | try expect(trunc(0.0) == 0.0); | |
| 112 | try expect(trunc(-0.0) == -0.0); | |
| 113 | try expect(math.isPositiveInf(trunc(math.inf(f64)))); | |
| 114 | try expect(math.isNegativeInf(trunc(-math.inf(f64)))); | |
| 115 | try expect(math.isNan(trunc(math.nan(f64)))); | |
| 116 | } | |
| 117 | ||
| 118 | test "trunc128.special" { | |
| 119 | try expect(truncq(0.0) == 0.0); | |
| 120 | try expect(truncq(-0.0) == -0.0); | |
| 121 | try expect(math.isPositiveInf(truncq(math.inf(f128)))); | |
| 122 | try expect(math.isNegativeInf(truncq(-math.inf(f128)))); | |
| 123 | try expect(math.isNan(truncq(math.nan(f128)))); | |
| 124 | } |
lib/std/testing.zig+1-1| ... | ... | @@ -265,7 +265,7 @@ pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance |
| 265 | 265 | test "expectApproxEqRel" { |
| 266 | 266 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { |
| 267 | 267 | const eps_value = comptime math.epsilon(T); |
| 268 | const sqrt_eps_value = comptime math.sqrt(eps_value); | |
| 268 | const sqrt_eps_value = comptime @sqrt(eps_value); | |
| 269 | 269 | |
| 270 | 270 | const pos_x: T = 12.0; |
| 271 | 271 | const pos_y: T = pos_x + 2 * eps_value; |
src/Sema.zig+2-2| ... | ... | @@ -14051,7 +14051,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 14051 | 14051 | const result_val = val.floatToInt(sema.arena, operand_ty, dest_ty, target) catch |err| switch (err) { |
| 14052 | 14052 | error.FloatCannotFit => { |
| 14053 | 14053 | return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{ |
| 14054 | std.math.floor(val.toFloat(f64)), | |
| 14054 | @floor(val.toFloat(f64)), | |
| 14055 | 14055 | dest_ty.fmt(sema.mod), |
| 14056 | 14056 | }); |
| 14057 | 14057 | }, |
| ... | ... | @@ -18371,7 +18371,7 @@ fn coerce( |
| 18371 | 18371 | } |
| 18372 | 18372 | const result_val = val.floatToInt(sema.arena, inst_ty, dest_ty, target) catch |err| switch (err) { |
| 18373 | 18373 | error.FloatCannotFit => { |
| 18374 | return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty.fmt(sema.mod) }); | |
| 18374 | return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ @floor(val.toFloat(f64)), dest_ty.fmt(sema.mod) }); | |
| 18375 | 18375 | }, |
| 18376 | 18376 | else => |e| return e, |
| 18377 | 18377 | }; |
src/translate_c.zig+1-1| ... | ... | @@ -3998,7 +3998,7 @@ fn transFloatingLiteral(c: *Context, scope: *Scope, expr: *const clang.FloatingL |
| 3998 | 3998 | var dbl = expr.getValueAsApproximateDouble(); |
| 3999 | 3999 | const is_negative = dbl < 0; |
| 4000 | 4000 | if (is_negative) dbl = -dbl; |
| 4001 | const str = if (dbl == std.math.floor(dbl)) | |
| 4001 | const str = if (dbl == @floor(dbl)) | |
| 4002 | 4002 | try std.fmt.allocPrint(c.arena, "{d}.0", .{dbl}) |
| 4003 | 4003 | else |
| 4004 | 4004 | try std.fmt.allocPrint(c.arena, "{d}", .{dbl}); |
src/value.zig+13-99| ... | ... | @@ -1155,6 +1155,7 @@ pub const Value = extern union { |
| 1155 | 1155 | 16 => return floatWriteToMemory(f16, val.toFloat(f16), target, buffer), |
| 1156 | 1156 | 32 => return floatWriteToMemory(f32, val.toFloat(f32), target, buffer), |
| 1157 | 1157 | 64 => return floatWriteToMemory(f64, val.toFloat(f64), target, buffer), |
| 1158 | 80 => return floatWriteToMemory(f80, val.toFloat(f80), target, buffer), | |
| 1158 | 1159 | 128 => return floatWriteToMemory(f128, val.toFloat(f128), target, buffer), |
| 1159 | 1160 | else => unreachable, |
| 1160 | 1161 | }, |
| ... | ... | @@ -1379,25 +1380,21 @@ pub const Value = extern union { |
| 1379 | 1380 | } |
| 1380 | 1381 | |
| 1381 | 1382 | fn floatWriteToMemory(comptime F: type, f: F, target: Target, buffer: []u8) void { |
| 1383 | const endian = target.cpu.arch.endian(); | |
| 1382 | 1384 | if (F == f80) { |
| 1383 | switch (target.cpu.arch) { | |
| 1384 | .i386, .x86_64 => { | |
| 1385 | const repr = std.math.break_f80(f); | |
| 1386 | std.mem.writeIntLittle(u64, buffer[0..8], repr.fraction); | |
| 1387 | std.mem.writeIntLittle(u16, buffer[8..10], repr.exp); | |
| 1388 | // TODO set the rest of the bytes to undefined. should we use 0xaa | |
| 1389 | // or is there a different way? | |
| 1390 | return; | |
| 1391 | }, | |
| 1392 | else => {}, | |
| 1393 | } | |
| 1385 | const repr = std.math.break_f80(f); | |
| 1386 | std.mem.writeInt(u64, buffer[0..8], repr.fraction, endian); | |
| 1387 | std.mem.writeInt(u16, buffer[8..10], repr.exp, endian); | |
| 1388 | // TODO set the rest of the bytes to undefined. should we use 0xaa | |
| 1389 | // or is there a different way? | |
| 1390 | return; | |
| 1394 | 1391 | } |
| 1395 | 1392 | const Int = @Type(.{ .Int = .{ |
| 1396 | 1393 | .signedness = .unsigned, |
| 1397 | 1394 | .bits = @typeInfo(F).Float.bits, |
| 1398 | 1395 | } }); |
| 1399 | 1396 | const int = @bitCast(Int, f); |
| 1400 | std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], int, target.cpu.arch.endian()); | |
| 1397 | std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], int, endian); | |
| 1401 | 1398 | } |
| 1402 | 1399 | |
| 1403 | 1400 | fn floatReadFromMemory(comptime F: type, target: Target, buffer: []const u8) F { |
| ... | ... | @@ -2869,9 +2866,7 @@ pub const Value = extern union { |
| 2869 | 2866 | 16 => return Value.Tag.float_16.create(arena, @intToFloat(f16, x)), |
| 2870 | 2867 | 32 => return Value.Tag.float_32.create(arena, @intToFloat(f32, x)), |
| 2871 | 2868 | 64 => return Value.Tag.float_64.create(arena, @intToFloat(f64, x)), |
| 2872 | // We can't lower this properly on non-x86 llvm backends yet | |
| 2873 | //80 => return Value.Tag.float_80.create(arena, @intToFloat(f80, x)), | |
| 2874 | 80 => @panic("TODO f80 intToFloat"), | |
| 2869 | 80 => return Value.Tag.float_80.create(arena, @intToFloat(f80, x)), | |
| 2875 | 2870 | 128 => return Value.Tag.float_128.create(arena, @intToFloat(f128, x)), |
| 2876 | 2871 | else => unreachable, |
| 2877 | 2872 | } |
| ... | ... | @@ -2908,9 +2903,9 @@ pub const Value = extern union { |
| 2908 | 2903 | } |
| 2909 | 2904 | |
| 2910 | 2905 | const isNegative = std.math.signbit(value); |
| 2911 | value = std.math.fabs(value); | |
| 2906 | value = @fabs(value); | |
| 2912 | 2907 | |
| 2913 | const floored = std.math.floor(value); | |
| 2908 | const floored = @floor(value); | |
| 2914 | 2909 | |
| 2915 | 2910 | var rational = try std.math.big.Rational.init(arena); |
| 2916 | 2911 | defer rational.deinit(); |
| ... | ... | @@ -2941,7 +2936,7 @@ pub const Value = extern union { |
| 2941 | 2936 | return 1; |
| 2942 | 2937 | } |
| 2943 | 2938 | |
| 2944 | const w_value = std.math.fabs(scalar); | |
| 2939 | const w_value = @fabs(scalar); | |
| 2945 | 2940 | return @divFloor(@floatToInt(std.math.big.Limb, std.math.log2(w_value)), @typeInfo(std.math.big.Limb).Int.bits) + 1; |
| 2946 | 2941 | } |
| 2947 | 2942 | |
| ... | ... | @@ -3737,9 +3732,6 @@ pub const Value = extern union { |
| 3737 | 3732 | return Value.Tag.float_64.create(arena, @rem(lhs_val, rhs_val)); |
| 3738 | 3733 | }, |
| 3739 | 3734 | 80 => { |
| 3740 | if (true) { | |
| 3741 | @panic("TODO implement compiler_rt __remx"); | |
| 3742 | } | |
| 3743 | 3735 | const lhs_val = lhs.toFloat(f80); |
| 3744 | 3736 | const rhs_val = rhs.toFloat(f80); |
| 3745 | 3737 | return Value.Tag.float_80.create(arena, @rem(lhs_val, rhs_val)); |
| ... | ... | @@ -3782,9 +3774,6 @@ pub const Value = extern union { |
| 3782 | 3774 | return Value.Tag.float_64.create(arena, @mod(lhs_val, rhs_val)); |
| 3783 | 3775 | }, |
| 3784 | 3776 | 80 => { |
| 3785 | if (true) { | |
| 3786 | @panic("TODO implement compiler_rt __modx"); | |
| 3787 | } | |
| 3788 | 3777 | const lhs_val = lhs.toFloat(f80); |
| 3789 | 3778 | const rhs_val = rhs.toFloat(f80); |
| 3790 | 3779 | return Value.Tag.float_80.create(arena, @mod(lhs_val, rhs_val)); |
| ... | ... | @@ -4198,9 +4187,6 @@ pub const Value = extern union { |
| 4198 | 4187 | return Value.Tag.float_64.create(arena, lhs_val / rhs_val); |
| 4199 | 4188 | }, |
| 4200 | 4189 | 80 => { |
| 4201 | if (true) { | |
| 4202 | @panic("TODO implement compiler_rt __divxf3"); | |
| 4203 | } | |
| 4204 | 4190 | const lhs_val = lhs.toFloat(f80); |
| 4205 | 4191 | const rhs_val = rhs.toFloat(f80); |
| 4206 | 4192 | return Value.Tag.float_80.create(arena, lhs_val / rhs_val); |
| ... | ... | @@ -4255,9 +4241,6 @@ pub const Value = extern union { |
| 4255 | 4241 | return Value.Tag.float_64.create(arena, @divFloor(lhs_val, rhs_val)); |
| 4256 | 4242 | }, |
| 4257 | 4243 | 80 => { |
| 4258 | if (true) { | |
| 4259 | @panic("TODO implement compiler_rt __floorx"); | |
| 4260 | } | |
| 4261 | 4244 | const lhs_val = lhs.toFloat(f80); |
| 4262 | 4245 | const rhs_val = rhs.toFloat(f80); |
| 4263 | 4246 | return Value.Tag.float_80.create(arena, @divFloor(lhs_val, rhs_val)); |
| ... | ... | @@ -4312,9 +4295,6 @@ pub const Value = extern union { |
| 4312 | 4295 | return Value.Tag.float_64.create(arena, @divTrunc(lhs_val, rhs_val)); |
| 4313 | 4296 | }, |
| 4314 | 4297 | 80 => { |
| 4315 | if (true) { | |
| 4316 | @panic("TODO implement compiler_rt __truncx"); | |
| 4317 | } | |
| 4318 | 4298 | const lhs_val = lhs.toFloat(f80); |
| 4319 | 4299 | const rhs_val = rhs.toFloat(f80); |
| 4320 | 4300 | return Value.Tag.float_80.create(arena, @divTrunc(lhs_val, rhs_val)); |
| ... | ... | @@ -4369,9 +4349,6 @@ pub const Value = extern union { |
| 4369 | 4349 | return Value.Tag.float_64.create(arena, lhs_val * rhs_val); |
| 4370 | 4350 | }, |
| 4371 | 4351 | 80 => { |
| 4372 | if (true) { | |
| 4373 | @panic("TODO implement compiler_rt __mulxf3"); | |
| 4374 | } | |
| 4375 | 4352 | const lhs_val = lhs.toFloat(f80); |
| 4376 | 4353 | const rhs_val = rhs.toFloat(f80); |
| 4377 | 4354 | return Value.Tag.float_80.create(arena, lhs_val * rhs_val); |
| ... | ... | @@ -4411,16 +4388,10 @@ pub const Value = extern union { |
| 4411 | 4388 | return Value.Tag.float_64.create(arena, @sqrt(f)); |
| 4412 | 4389 | }, |
| 4413 | 4390 | 80 => { |
| 4414 | if (true) { | |
| 4415 | @panic("TODO implement compiler_rt __sqrtx"); | |
| 4416 | } | |
| 4417 | 4391 | const f = val.toFloat(f80); |
| 4418 | 4392 | return Value.Tag.float_80.create(arena, @sqrt(f)); |
| 4419 | 4393 | }, |
| 4420 | 4394 | 128 => { |
| 4421 | if (true) { | |
| 4422 | @panic("TODO implement compiler_rt sqrtq"); | |
| 4423 | } | |
| 4424 | 4395 | const f = val.toFloat(f128); |
| 4425 | 4396 | return Value.Tag.float_128.create(arena, @sqrt(f)); |
| 4426 | 4397 | }, |
| ... | ... | @@ -4454,16 +4425,10 @@ pub const Value = extern union { |
| 4454 | 4425 | return Value.Tag.float_64.create(arena, @sin(f)); |
| 4455 | 4426 | }, |
| 4456 | 4427 | 80 => { |
| 4457 | if (true) { | |
| 4458 | @panic("TODO implement compiler_rt sin for f80"); | |
| 4459 | } | |
| 4460 | 4428 | const f = val.toFloat(f80); |
| 4461 | 4429 | return Value.Tag.float_80.create(arena, @sin(f)); |
| 4462 | 4430 | }, |
| 4463 | 4431 | 128 => { |
| 4464 | if (true) { | |
| 4465 | @panic("TODO implement compiler_rt sin for f128"); | |
| 4466 | } | |
| 4467 | 4432 | const f = val.toFloat(f128); |
| 4468 | 4433 | return Value.Tag.float_128.create(arena, @sin(f)); |
| 4469 | 4434 | }, |
| ... | ... | @@ -4497,16 +4462,10 @@ pub const Value = extern union { |
| 4497 | 4462 | return Value.Tag.float_64.create(arena, @cos(f)); |
| 4498 | 4463 | }, |
| 4499 | 4464 | 80 => { |
| 4500 | if (true) { | |
| 4501 | @panic("TODO implement compiler_rt cos for f80"); | |
| 4502 | } | |
| 4503 | 4465 | const f = val.toFloat(f80); |
| 4504 | 4466 | return Value.Tag.float_80.create(arena, @cos(f)); |
| 4505 | 4467 | }, |
| 4506 | 4468 | 128 => { |
| 4507 | if (true) { | |
| 4508 | @panic("TODO implement compiler_rt cos for f128"); | |
| 4509 | } | |
| 4510 | 4469 | const f = val.toFloat(f128); |
| 4511 | 4470 | return Value.Tag.float_128.create(arena, @cos(f)); |
| 4512 | 4471 | }, |
| ... | ... | @@ -4540,16 +4499,10 @@ pub const Value = extern union { |
| 4540 | 4499 | return Value.Tag.float_64.create(arena, @exp(f)); |
| 4541 | 4500 | }, |
| 4542 | 4501 | 80 => { |
| 4543 | if (true) { | |
| 4544 | @panic("TODO implement compiler_rt exp for f80"); | |
| 4545 | } | |
| 4546 | 4502 | const f = val.toFloat(f80); |
| 4547 | 4503 | return Value.Tag.float_80.create(arena, @exp(f)); |
| 4548 | 4504 | }, |
| 4549 | 4505 | 128 => { |
| 4550 | if (true) { | |
| 4551 | @panic("TODO implement compiler_rt exp for f128"); | |
| 4552 | } | |
| 4553 | 4506 | const f = val.toFloat(f128); |
| 4554 | 4507 | return Value.Tag.float_128.create(arena, @exp(f)); |
| 4555 | 4508 | }, |
| ... | ... | @@ -4583,16 +4536,10 @@ pub const Value = extern union { |
| 4583 | 4536 | return Value.Tag.float_64.create(arena, @exp2(f)); |
| 4584 | 4537 | }, |
| 4585 | 4538 | 80 => { |
| 4586 | if (true) { | |
| 4587 | @panic("TODO implement compiler_rt exp2 for f80"); | |
| 4588 | } | |
| 4589 | 4539 | const f = val.toFloat(f80); |
| 4590 | 4540 | return Value.Tag.float_80.create(arena, @exp2(f)); |
| 4591 | 4541 | }, |
| 4592 | 4542 | 128 => { |
| 4593 | if (true) { | |
| 4594 | @panic("TODO implement compiler_rt exp2 for f128"); | |
| 4595 | } | |
| 4596 | 4543 | const f = val.toFloat(f128); |
| 4597 | 4544 | return Value.Tag.float_128.create(arena, @exp2(f)); |
| 4598 | 4545 | }, |
| ... | ... | @@ -4626,16 +4573,10 @@ pub const Value = extern union { |
| 4626 | 4573 | return Value.Tag.float_64.create(arena, @log(f)); |
| 4627 | 4574 | }, |
| 4628 | 4575 | 80 => { |
| 4629 | if (true) { | |
| 4630 | @panic("TODO implement compiler_rt log for f80"); | |
| 4631 | } | |
| 4632 | 4576 | const f = val.toFloat(f80); |
| 4633 | 4577 | return Value.Tag.float_80.create(arena, @log(f)); |
| 4634 | 4578 | }, |
| 4635 | 4579 | 128 => { |
| 4636 | if (true) { | |
| 4637 | @panic("TODO implement compiler_rt log for f128"); | |
| 4638 | } | |
| 4639 | 4580 | const f = val.toFloat(f128); |
| 4640 | 4581 | return Value.Tag.float_128.create(arena, @log(f)); |
| 4641 | 4582 | }, |
| ... | ... | @@ -4669,16 +4610,10 @@ pub const Value = extern union { |
| 4669 | 4610 | return Value.Tag.float_64.create(arena, @log2(f)); |
| 4670 | 4611 | }, |
| 4671 | 4612 | 80 => { |
| 4672 | if (true) { | |
| 4673 | @panic("TODO implement compiler_rt log2 for f80"); | |
| 4674 | } | |
| 4675 | 4613 | const f = val.toFloat(f80); |
| 4676 | 4614 | return Value.Tag.float_80.create(arena, @log2(f)); |
| 4677 | 4615 | }, |
| 4678 | 4616 | 128 => { |
| 4679 | if (true) { | |
| 4680 | @panic("TODO implement compiler_rt log2 for f128"); | |
| 4681 | } | |
| 4682 | 4617 | const f = val.toFloat(f128); |
| 4683 | 4618 | return Value.Tag.float_128.create(arena, @log2(f)); |
| 4684 | 4619 | }, |
| ... | ... | @@ -4712,16 +4647,10 @@ pub const Value = extern union { |
| 4712 | 4647 | return Value.Tag.float_64.create(arena, @log10(f)); |
| 4713 | 4648 | }, |
| 4714 | 4649 | 80 => { |
| 4715 | if (true) { | |
| 4716 | @panic("TODO implement compiler_rt log10 for f80"); | |
| 4717 | } | |
| 4718 | 4650 | const f = val.toFloat(f80); |
| 4719 | 4651 | return Value.Tag.float_80.create(arena, @log10(f)); |
| 4720 | 4652 | }, |
| 4721 | 4653 | 128 => { |
| 4722 | if (true) { | |
| 4723 | @panic("TODO implement compiler_rt log10 for f128"); | |
| 4724 | } | |
| 4725 | 4654 | const f = val.toFloat(f128); |
| 4726 | 4655 | return Value.Tag.float_128.create(arena, @log10(f)); |
| 4727 | 4656 | }, |
| ... | ... | @@ -4755,9 +4684,6 @@ pub const Value = extern union { |
| 4755 | 4684 | return Value.Tag.float_64.create(arena, @fabs(f)); |
| 4756 | 4685 | }, |
| 4757 | 4686 | 80 => { |
| 4758 | if (true) { | |
| 4759 | @panic("TODO implement compiler_rt fabs for f80 (__fabsx)"); | |
| 4760 | } | |
| 4761 | 4687 | const f = val.toFloat(f80); |
| 4762 | 4688 | return Value.Tag.float_80.create(arena, @fabs(f)); |
| 4763 | 4689 | }, |
| ... | ... | @@ -4795,9 +4721,6 @@ pub const Value = extern union { |
| 4795 | 4721 | return Value.Tag.float_64.create(arena, @floor(f)); |
| 4796 | 4722 | }, |
| 4797 | 4723 | 80 => { |
| 4798 | if (true) { | |
| 4799 | @panic("TODO implement compiler_rt floor for f80 (__floorx)"); | |
| 4800 | } | |
| 4801 | 4724 | const f = val.toFloat(f80); |
| 4802 | 4725 | return Value.Tag.float_80.create(arena, @floor(f)); |
| 4803 | 4726 | }, |
| ... | ... | @@ -4835,9 +4758,6 @@ pub const Value = extern union { |
| 4835 | 4758 | return Value.Tag.float_64.create(arena, @ceil(f)); |
| 4836 | 4759 | }, |
| 4837 | 4760 | 80 => { |
| 4838 | if (true) { | |
| 4839 | @panic("TODO implement compiler_rt ceil for f80"); | |
| 4840 | } | |
| 4841 | 4761 | const f = val.toFloat(f80); |
| 4842 | 4762 | return Value.Tag.float_80.create(arena, @ceil(f)); |
| 4843 | 4763 | }, |
| ... | ... | @@ -4875,9 +4795,6 @@ pub const Value = extern union { |
| 4875 | 4795 | return Value.Tag.float_64.create(arena, @round(f)); |
| 4876 | 4796 | }, |
| 4877 | 4797 | 80 => { |
| 4878 | if (true) { | |
| 4879 | @panic("TODO implement compiler_rt round for f80"); | |
| 4880 | } | |
| 4881 | 4798 | const f = val.toFloat(f80); |
| 4882 | 4799 | return Value.Tag.float_80.create(arena, @round(f)); |
| 4883 | 4800 | }, |
| ... | ... | @@ -4915,9 +4832,6 @@ pub const Value = extern union { |
| 4915 | 4832 | return Value.Tag.float_64.create(arena, @trunc(f)); |
| 4916 | 4833 | }, |
| 4917 | 4834 | 80 => { |
| 4918 | if (true) { | |
| 4919 | @panic("TODO implement compiler_rt trunc for f80"); | |
| 4920 | } | |
| 4921 | 4835 | const f = val.toFloat(f80); |
| 4922 | 4836 | return Value.Tag.float_80.create(arena, @trunc(f)); |
| 4923 | 4837 | }, |
test/behavior/math.zig+54-16| ... | ... | @@ -6,6 +6,7 @@ const expectEqualSlices = std.testing.expectEqualSlices; |
| 6 | 6 | const maxInt = std.math.maxInt; |
| 7 | 7 | const minInt = std.math.minInt; |
| 8 | 8 | const mem = std.mem; |
| 9 | const math = std.math; | |
| 9 | 10 | |
| 10 | 11 | test "assignment operators" { |
| 11 | 12 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -947,13 +948,13 @@ fn frem(comptime T: type) !void { |
| 947 | 948 | else => unreachable, |
| 948 | 949 | }; |
| 949 | 950 | |
| 950 | try expect(std.math.fabs(@rem(@as(T, 6.9), @as(T, 4.0)) - @as(T, 2.9)) < epsilon); | |
| 951 | try expect(std.math.fabs(@rem(@as(T, -6.9), @as(T, 4.0)) - @as(T, -2.9)) < epsilon); | |
| 952 | try expect(std.math.fabs(@rem(@as(T, -5.0), @as(T, 3.0)) - @as(T, -2.0)) < epsilon); | |
| 953 | try expect(std.math.fabs(@rem(@as(T, 3.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon); | |
| 954 | try expect(std.math.fabs(@rem(@as(T, 1.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon); | |
| 955 | try expect(std.math.fabs(@rem(@as(T, 0.0), @as(T, 1.0)) - @as(T, 0.0)) < epsilon); | |
| 956 | try expect(std.math.fabs(@rem(@as(T, -0.0), @as(T, 1.0)) - @as(T, -0.0)) < epsilon); | |
| 951 | try expect(@fabs(@rem(@as(T, 6.9), @as(T, 4.0)) - @as(T, 2.9)) < epsilon); | |
| 952 | try expect(@fabs(@rem(@as(T, -6.9), @as(T, 4.0)) - @as(T, -2.9)) < epsilon); | |
| 953 | try expect(@fabs(@rem(@as(T, -5.0), @as(T, 3.0)) - @as(T, -2.0)) < epsilon); | |
| 954 | try expect(@fabs(@rem(@as(T, 3.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon); | |
| 955 | try expect(@fabs(@rem(@as(T, 1.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon); | |
| 956 | try expect(@fabs(@rem(@as(T, 0.0), @as(T, 1.0)) - @as(T, 0.0)) < epsilon); | |
| 957 | try expect(@fabs(@rem(@as(T, -0.0), @as(T, 1.0)) - @as(T, -0.0)) < epsilon); | |
| 957 | 958 | } |
| 958 | 959 | |
| 959 | 960 | test "float modulo division using @mod" { |
| ... | ... | @@ -978,13 +979,13 @@ fn fmod(comptime T: type) !void { |
| 978 | 979 | else => unreachable, |
| 979 | 980 | }; |
| 980 | 981 | |
| 981 | try expect(std.math.fabs(@mod(@as(T, 6.9), @as(T, 4.0)) - @as(T, 2.9)) < epsilon); | |
| 982 | try expect(std.math.fabs(@mod(@as(T, -6.9), @as(T, 4.0)) - @as(T, 1.1)) < epsilon); | |
| 983 | try expect(std.math.fabs(@mod(@as(T, -5.0), @as(T, 3.0)) - @as(T, 1.0)) < epsilon); | |
| 984 | try expect(std.math.fabs(@mod(@as(T, 3.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon); | |
| 985 | try expect(std.math.fabs(@mod(@as(T, 1.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon); | |
| 986 | try expect(std.math.fabs(@mod(@as(T, 0.0), @as(T, 1.0)) - @as(T, 0.0)) < epsilon); | |
| 987 | try expect(std.math.fabs(@mod(@as(T, -0.0), @as(T, 1.0)) - @as(T, -0.0)) < epsilon); | |
| 982 | try expect(@fabs(@mod(@as(T, 6.9), @as(T, 4.0)) - @as(T, 2.9)) < epsilon); | |
| 983 | try expect(@fabs(@mod(@as(T, -6.9), @as(T, 4.0)) - @as(T, 1.1)) < epsilon); | |
| 984 | try expect(@fabs(@mod(@as(T, -5.0), @as(T, 3.0)) - @as(T, 1.0)) < epsilon); | |
| 985 | try expect(@fabs(@mod(@as(T, 3.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon); | |
| 986 | try expect(@fabs(@mod(@as(T, 1.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon); | |
| 987 | try expect(@fabs(@mod(@as(T, 0.0), @as(T, 1.0)) - @as(T, 0.0)) < epsilon); | |
| 988 | try expect(@fabs(@mod(@as(T, -0.0), @as(T, 1.0)) - @as(T, -0.0)) < epsilon); | |
| 988 | 989 | } |
| 989 | 990 | |
| 990 | 991 | test "@sqrt" { |
| ... | ... | @@ -1288,8 +1289,8 @@ test "NaN comparison f80" { |
| 1288 | 1289 | } |
| 1289 | 1290 | |
| 1290 | 1291 | fn testNanEqNan(comptime F: type) !void { |
| 1291 | var nan1 = std.math.nan(F); | |
| 1292 | var nan2 = std.math.nan(F); | |
| 1292 | var nan1 = math.nan(F); | |
| 1293 | var nan2 = math.nan(F); | |
| 1293 | 1294 | try expect(nan1 != nan2); |
| 1294 | 1295 | try expect(!(nan1 == nan2)); |
| 1295 | 1296 | try expect(!(nan1 > nan2)); |
| ... | ... | @@ -1346,3 +1347,40 @@ test "signed zeros are represented properly" { |
| 1346 | 1347 | try S.doTheTest(); |
| 1347 | 1348 | comptime try S.doTheTest(); |
| 1348 | 1349 | } |
| 1350 | ||
| 1351 | test "comptime sin and ln" { | |
| 1352 | const v = comptime (@sin(@as(f32, 1)) + @log(@as(f32, 5))); | |
| 1353 | try expect(v == @sin(@as(f32, 1)) + @log(@as(f32, 5))); | |
| 1354 | } | |
| 1355 | ||
| 1356 | test "fabs" { | |
| 1357 | inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| { | |
| 1358 | // normals | |
| 1359 | try expect(@fabs(@as(T, 1.0)) == 1.0); | |
| 1360 | try expect(@fabs(@as(T, -1.0)) == 1.0); | |
| 1361 | try expect(@fabs(math.floatMin(T)) == math.floatMin(T)); | |
| 1362 | try expect(@fabs(-math.floatMin(T)) == math.floatMin(T)); | |
| 1363 | try expect(@fabs(math.floatMax(T)) == math.floatMax(T)); | |
| 1364 | try expect(@fabs(-math.floatMax(T)) == math.floatMax(T)); | |
| 1365 | ||
| 1366 | // subnormals | |
| 1367 | try expect(@fabs(@as(T, 0.0)) == 0.0); | |
| 1368 | try expect(@fabs(@as(T, -0.0)) == 0.0); | |
| 1369 | try expect(@fabs(math.floatTrueMin(T)) == math.floatTrueMin(T)); | |
| 1370 | try expect(@fabs(-math.floatTrueMin(T)) == math.floatTrueMin(T)); | |
| 1371 | ||
| 1372 | // non-finite numbers | |
| 1373 | try expect(math.isPositiveInf(@fabs(math.inf(T)))); | |
| 1374 | try expect(math.isPositiveInf(@fabs(-math.inf(T)))); | |
| 1375 | try expect(math.isNan(@fabs(math.nan(T)))); | |
| 1376 | } | |
| 1377 | } | |
| 1378 | ||
| 1379 | test "absFloat" { | |
| 1380 | try testAbsFloat(); | |
| 1381 | comptime try testAbsFloat(); | |
| 1382 | } | |
| 1383 | fn testAbsFloat() !void { | |
| 1384 | try expect(@fabs(@as(f32, -10.05)) == @as(f32, 10.05)); | |
| 1385 | try expect(@fabs(@as(f32, 10.05)) == @as(f32, 10.05)); | |
| 1386 | } |