add math.isNaN (#16179)
* add math.isNaN * isNaN now works with --passc:-ffast-math; tests * Update lib/pure/math.nim Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
parent
bb1c962286
commit
0b73106ccf
4 changed files with 50 additions and 5 deletions
|
|
@ -58,6 +58,8 @@
|
||||||
- `strscans.scanf` now supports parsing single characters.
|
- `strscans.scanf` now supports parsing single characters.
|
||||||
|
|
||||||
|
|
||||||
|
- Added `math.isNaN`.
|
||||||
|
|
||||||
## Language changes
|
## Language changes
|
||||||
|
|
||||||
- `nimscript` now handles `except Exception as e`.
|
- `nimscript` now handles `except Exception as e`.
|
||||||
|
|
|
||||||
|
|
@ -1683,6 +1683,7 @@ proc decodeURIComponent*(uri: cstring): cstring {.importc, nodecl.}
|
||||||
proc encodeURIComponent*(uri: cstring): cstring {.importc, nodecl.}
|
proc encodeURIComponent*(uri: cstring): cstring {.importc, nodecl.}
|
||||||
proc isFinite*(x: BiggestFloat): bool {.importc, nodecl.}
|
proc isFinite*(x: BiggestFloat): bool {.importc, nodecl.}
|
||||||
proc isNaN*(x: BiggestFloat): bool {.importc, nodecl.}
|
proc isNaN*(x: BiggestFloat): bool {.importc, nodecl.}
|
||||||
|
## see also `math.isNaN`.
|
||||||
|
|
||||||
proc newEvent*(name: cstring): Event {.importcpp: "new Event(@)", constructor.}
|
proc newEvent*(name: cstring): Event {.importcpp: "new Event(@)", constructor.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,10 @@ import std/private/since
|
||||||
|
|
||||||
import bitops, fenv
|
import bitops, fenv
|
||||||
|
|
||||||
|
when defined(c) or defined(cpp):
|
||||||
|
proc c_isnan(x: float): bool {.importc: "isnan", header: "<math.h>".}
|
||||||
|
# a generic like `x: SomeFloat` might work too if this is implemented via a C macro.
|
||||||
|
|
||||||
func binom*(n, k: int): int =
|
func binom*(n, k: int): int =
|
||||||
## Computes the `binomial coefficient <https://en.wikipedia.org/wiki/Binomial_coefficient>`_.
|
## Computes the `binomial coefficient <https://en.wikipedia.org/wiki/Binomial_coefficient>`_.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -133,10 +137,27 @@ type
|
||||||
fcInf, ## value is positive infinity
|
fcInf, ## value is positive infinity
|
||||||
fcNegInf ## value is negative infinity
|
fcNegInf ## value is negative infinity
|
||||||
|
|
||||||
|
func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} =
|
||||||
|
## Returns whether `x` is a `NaN`, more efficiently than via `classify(x) == fcNan`.
|
||||||
|
## Works even with: `--passc:-ffast-math`.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert NaN.isNaN
|
||||||
|
doAssert not Inf.isNaN
|
||||||
|
doAssert isNaN(Inf - Inf)
|
||||||
|
doAssert not isNan(3.1415926)
|
||||||
|
doAssert not isNan(0'f32)
|
||||||
|
|
||||||
|
template fn: untyped = result = x != x
|
||||||
|
when nimvm: fn()
|
||||||
|
else:
|
||||||
|
when defined(js): fn()
|
||||||
|
else: result = c_isnan(x)
|
||||||
|
|
||||||
func classify*(x: float): FloatClass =
|
func classify*(x: float): FloatClass =
|
||||||
## Classifies a floating point value.
|
## Classifies a floating point value.
|
||||||
##
|
##
|
||||||
## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_.
|
## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_.
|
||||||
|
## Doesn't work with: `--passc:-ffast-math`.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert classify(0.3) == fcNormal
|
doAssert classify(0.3) == fcNormal
|
||||||
doAssert classify(0.0) == fcZero
|
doAssert classify(0.0) == fcZero
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,11 @@ discard """
|
||||||
|
|
||||||
[Suite] ^
|
[Suite] ^
|
||||||
'''
|
'''
|
||||||
|
matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# xxx: fix bugs for js then add: targets:"c js"
|
||||||
|
|
||||||
import math, random, os
|
import math, random, os
|
||||||
import unittest
|
import unittest
|
||||||
import sets, tables
|
import sets, tables
|
||||||
|
|
@ -37,12 +40,16 @@ suite "random int":
|
||||||
var rand: int
|
var rand: int
|
||||||
for i in 1..1000:
|
for i in 1..1000:
|
||||||
rand = rand(100..1000)
|
rand = rand(100..1000)
|
||||||
check rand < 1000
|
when defined(js): # xxx bug: otherwise fails
|
||||||
|
check rand <= 1000
|
||||||
|
else:
|
||||||
|
check rand < 1000
|
||||||
check rand >= 100
|
check rand >= 100
|
||||||
test " again gives new numbers":
|
test " again gives new numbers":
|
||||||
|
|
||||||
var rand1 = rand(1000000)
|
var rand1 = rand(1000000)
|
||||||
os.sleep(200)
|
when not defined(js):
|
||||||
|
os.sleep(200)
|
||||||
|
|
||||||
var rand2 = rand(1000000)
|
var rand2 = rand(1000000)
|
||||||
check rand1 != rand2
|
check rand1 != rand2
|
||||||
|
|
@ -72,7 +79,8 @@ suite "random float":
|
||||||
test " again gives new numbers":
|
test " again gives new numbers":
|
||||||
|
|
||||||
var rand1:float = rand(1000000.0)
|
var rand1:float = rand(1000000.0)
|
||||||
os.sleep(200)
|
when not defined(js):
|
||||||
|
os.sleep(200)
|
||||||
|
|
||||||
var rand2:float = rand(1000000.0)
|
var rand2:float = rand(1000000.0)
|
||||||
check rand1 != rand2
|
check rand1 != rand2
|
||||||
|
|
@ -151,6 +159,7 @@ block:
|
||||||
when not defined(js):
|
when not defined(js):
|
||||||
# Check for no side effect annotation
|
# Check for no side effect annotation
|
||||||
proc mySqrt(num: float): float {.noSideEffect.} =
|
proc mySqrt(num: float): float {.noSideEffect.} =
|
||||||
|
# xxx unused
|
||||||
return sqrt(num)
|
return sqrt(num)
|
||||||
|
|
||||||
# check gamma function
|
# check gamma function
|
||||||
|
|
@ -194,7 +203,8 @@ block:
|
||||||
#special case
|
#special case
|
||||||
doAssert(classify(trunc(1e1000000)) == fcInf)
|
doAssert(classify(trunc(1e1000000)) == fcInf)
|
||||||
doAssert(classify(trunc(-1e1000000)) == fcNegInf)
|
doAssert(classify(trunc(-1e1000000)) == fcNegInf)
|
||||||
doAssert(classify(trunc(0.0/0.0)) == fcNan)
|
when not defined(nimTmathCase2):
|
||||||
|
doAssert(classify(trunc(0.0/0.0)) == fcNan)
|
||||||
doAssert(classify(trunc(0.0)) == fcZero)
|
doAssert(classify(trunc(0.0)) == fcZero)
|
||||||
|
|
||||||
#trick the compiler to produce signed zero
|
#trick the compiler to produce signed zero
|
||||||
|
|
@ -211,7 +221,8 @@ block:
|
||||||
doAssert(trunc(0.1'f32) == 0)
|
doAssert(trunc(0.1'f32) == 0)
|
||||||
doAssert(classify(trunc(1e1000000'f32)) == fcInf)
|
doAssert(classify(trunc(1e1000000'f32)) == fcInf)
|
||||||
doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf)
|
doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf)
|
||||||
doAssert(classify(trunc(f_nan.float32)) == fcNan)
|
when not defined(nimTmathCase2):
|
||||||
|
doAssert(classify(trunc(f_nan.float32)) == fcNan)
|
||||||
doAssert(classify(trunc(0.0'f32)) == fcZero)
|
doAssert(classify(trunc(0.0'f32)) == fcZero)
|
||||||
|
|
||||||
block: # sgn() tests
|
block: # sgn() tests
|
||||||
|
|
@ -272,3 +283,13 @@ block:
|
||||||
doAssert log2(2.0'f32) == 1.0'f32
|
doAssert log2(2.0'f32) == 1.0'f32
|
||||||
doAssert log2(1.0'f32) == 0.0'f32
|
doAssert log2(1.0'f32) == 0.0'f32
|
||||||
doAssert classify(log2(0.0'f32)) == fcNegInf
|
doAssert classify(log2(0.0'f32)) == fcNegInf
|
||||||
|
|
||||||
|
template main =
|
||||||
|
# xxx wrap all under `main` so it also gets tested in vm.
|
||||||
|
block: # isNaN
|
||||||
|
doAssert NaN.isNaN
|
||||||
|
doAssert not Inf.isNaN
|
||||||
|
doAssert isNaN(Inf - Inf)
|
||||||
|
|
||||||
|
main()
|
||||||
|
static: main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue