mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 07:21:19 +00:00
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:
@@ -58,6 +58,8 @@
|
||||
- `strscans.scanf` now supports parsing single characters.
|
||||
|
||||
|
||||
- Added `math.isNaN`.
|
||||
|
||||
## Language changes
|
||||
|
||||
- `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 isFinite*(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.}
|
||||
|
||||
|
||||
@@ -58,6 +58,10 @@ import std/private/since
|
||||
|
||||
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 =
|
||||
## Computes the `binomial coefficient <https://en.wikipedia.org/wiki/Binomial_coefficient>`_.
|
||||
runnableExamples:
|
||||
@@ -133,10 +137,27 @@ type
|
||||
fcInf, ## value is positive 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 =
|
||||
## Classifies a floating point value.
|
||||
##
|
||||
## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_.
|
||||
## Doesn't work with: `--passc:-ffast-math`.
|
||||
runnableExamples:
|
||||
doAssert classify(0.3) == fcNormal
|
||||
doAssert classify(0.0) == fcZero
|
||||
|
||||
@@ -12,8 +12,11 @@ discard """
|
||||
|
||||
[Suite] ^
|
||||
'''
|
||||
matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math"
|
||||
"""
|
||||
|
||||
# xxx: fix bugs for js then add: targets:"c js"
|
||||
|
||||
import math, random, os
|
||||
import unittest
|
||||
import sets, tables
|
||||
@@ -37,12 +40,16 @@ suite "random int":
|
||||
var rand: int
|
||||
for i in 1..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
|
||||
test " again gives new numbers":
|
||||
|
||||
var rand1 = rand(1000000)
|
||||
os.sleep(200)
|
||||
when not defined(js):
|
||||
os.sleep(200)
|
||||
|
||||
var rand2 = rand(1000000)
|
||||
check rand1 != rand2
|
||||
@@ -72,7 +79,8 @@ suite "random float":
|
||||
test " again gives new numbers":
|
||||
|
||||
var rand1:float = rand(1000000.0)
|
||||
os.sleep(200)
|
||||
when not defined(js):
|
||||
os.sleep(200)
|
||||
|
||||
var rand2:float = rand(1000000.0)
|
||||
check rand1 != rand2
|
||||
@@ -151,6 +159,7 @@ block:
|
||||
when not defined(js):
|
||||
# Check for no side effect annotation
|
||||
proc mySqrt(num: float): float {.noSideEffect.} =
|
||||
# xxx unused
|
||||
return sqrt(num)
|
||||
|
||||
# check gamma function
|
||||
@@ -194,7 +203,8 @@ block:
|
||||
#special case
|
||||
doAssert(classify(trunc(1e1000000)) == fcInf)
|
||||
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)
|
||||
|
||||
#trick the compiler to produce signed zero
|
||||
@@ -211,7 +221,8 @@ block:
|
||||
doAssert(trunc(0.1'f32) == 0)
|
||||
doAssert(classify(trunc(1e1000000'f32)) == fcInf)
|
||||
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)
|
||||
|
||||
block: # sgn() tests
|
||||
@@ -272,3 +283,13 @@ block:
|
||||
doAssert log2(2.0'f32) == 1.0'f32
|
||||
doAssert log2(1.0'f32) == 0.0'f32
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user