diff options
-rw-r--r-- | lib/pure/math.nim | 45 | ||||
-rw-r--r-- | tests/stdlib/tmath.nim | 33 | ||||
-rw-r--r-- | tests/vm/tcastint.nim | 14 |
3 files changed, 48 insertions, 44 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 = diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 894c79369..769d89b64 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -197,6 +197,14 @@ template main() = doAssert: compiles(5.5 ^ 2.uint8) doAssert: not compiles(5.5 ^ 2.2) + block: # isNaN + doAssert NaN.isNaN + doAssert not Inf.isNaN + doAssert isNaN(Inf - Inf) + doAssert not isNaN(0.0) + doAssert not isNaN(3.1415926) + doAssert not isNaN(0'f32) + block: # signbit doAssert not signbit(0.0) doAssert signbit(-0.0) @@ -207,14 +215,6 @@ template main() = doAssert signbit(-Inf) doAssert not signbit(NaN) - block: # isNaN - doAssert NaN.isNaN - doAssert not Inf.isNaN - doAssert isNaN(Inf - Inf) - doAssert not isNaN(3.1415926) - doAssert not isNaN(0'f32) - - block: # signbit let x1 = NaN let x2 = -NaN let x3 = -x1 @@ -269,6 +269,10 @@ template main() = doAssert copySign(-NaN, 0.0).isNaN doAssert copySign(-NaN, -0.0).isNaN + doAssert copySign(-1.0, NaN) == 1.0 + doAssert copySign(-1.0, -NaN) == -1.0 + doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 + block: # almostEqual doAssert almostEqual(3.141592653589793, 3.1415926535897936) doAssert almostEqual(1.6777215e7'f32, 1.6777216e7'f32) @@ -279,7 +283,7 @@ template main() = doAssert not almostEqual(Inf, NaN) doAssert not almostEqual(NaN, NaN) - block: # round() tests + block: # round block: # Round to 0 decimal places doAssert round(54.652) == 55.0 doAssert round(54.352) == 54.0 @@ -300,6 +304,7 @@ template main() = doAssert round(2.5) == 3.0 doAssert round(2.5'f32) == 3.0'f32 doAssert round(2.5'f64) == 3.0'f64 + block: # func round*[T: float32|float64](x: T, places: int): T doAssert round(54.345, 0) == 54.0 template fn(x) = @@ -311,15 +316,7 @@ template main() = fn(54.346) fn(54.346'f32) - when nimvm: - discard - else: - when not defined(js): - doAssert copySign(-1.0, -NaN) == -1.0 - doAssert copySign(10.0, -NaN) == -10.0 - doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 # fails in VM - - block: + block: # abs doAssert 1.0 / abs(-0.0) == Inf doAssert 1.0 / abs(0.0) == Inf doAssert -1.0 / abs(-0.0) == -Inf diff --git a/tests/vm/tcastint.nim b/tests/vm/tcastint.nim index acff0d2b1..a97c81ed2 100644 --- a/tests/vm/tcastint.nim +++ b/tests/vm/tcastint.nim @@ -1,7 +1,3 @@ -discard """ - output: "OK" -""" - import macros type @@ -292,16 +288,12 @@ proc test_float32_castB() = # any surprising content. doAssert cast[uint64](c) == 3270918144'u64 -test() -test_float_cast() -test_float32_cast() -free_integer_casting() -test_float32_castB() -static: +template main() = test() test_float_cast() test_float32_cast() free_integer_casting() test_float32_castB() -echo "OK" +static: main() +main() |