diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2021-02-21 23:47:00 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-22 08:47:00 +0100 |
commit | cde950e1bc4f8fa3ac9b243cb6117dab1eab3645 (patch) | |
tree | 9aa61a808d264a6c197e58c41441dba4b73f55b3 /lib | |
parent | 04b11203343b76cb854fcba66cf25d5f7bba3683 (diff) | |
download | Nim-cde950e1bc4f8fa3ac9b243cb6117dab1eab3645.tar.gz |
make copySign for js consistent with other backends (#16609)
* make copySign work more robustly in js * improve tests * improve tests/vm/tcastint.nim
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/math.nim | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 577fa47a5..9e48ecf5d 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -175,11 +175,24 @@ when defined(js): proc toBitsImpl(x: float): array[2, uint32] = let buffer = newArrayBuffer(8) - let floatBuffer = newFloat64Array(buffer) - let uintBuffer = newUint32Array(buffer) - floatBuffer[0] = x - {.emit: "`result` = `uintBuffer`;".} - # result = cast[array[2, uint32]](uintBuffer) + let a = newFloat64Array(buffer) + let b = newUint32Array(buffer) + a[0] = x + {.emit: "`result` = `b`;".} + # result = cast[array[2, uint32]](b) + + proc jsSetSign(x: float, sgn: bool): float = + let buffer = newArrayBuffer(8) + let a = newFloat64Array(buffer) + let b = newUint32Array(buffer) + a[0] = x + asm """ + function updateBit(num, bitPos, bitVal) { + return (num & ~(1 << bitPos)) | (bitVal << bitPos); + } + `b`[1] = updateBit(`b`[1], 31, `sgn`); + `result` = `a`[0] + """ proc signbit*(x: SomeFloat): bool {.inline, since: (1, 5, 1).} = ## Returns true if `x` is negative, false otherwise. @@ -203,19 +216,21 @@ func copySign*[T: SomeFloat](x, y: T): T {.inline, since: (1, 5, 1).} = doAssert copySign(10.0, -1.0) == -10.0 doAssert copySign(-Inf, -0.0) == -Inf doAssert copySign(NaN, 1.0).isNaN + doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 # TODO: use signbit for examples - template impl() = - if y > 0.0 or (y == 0.0 and 1.0 / y > 0.0): - result = abs(x) - elif y <= 0.0: - result = -abs(x) - else: # must be NaN - result = abs(x) - - when defined(js): impl() + when defined(js): + let uintBuffer = toBitsImpl(y) + let sgn = (uintBuffer[1] shr 31) != 0 + result = jsSetSign(x, sgn) else: - when nimvm: impl() + when nimvm: # not exact but we have a vmops for recent enough nim + if y > 0.0 or (y == 0.0 and 1.0 / y > 0.0): + result = abs(x) + elif y <= 0.0: + result = -abs(x) + else: # must be NaN + result = abs(x) else: result = c_copysign(x, y) func classify*(x: float): FloatClass = |