-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cast[uint](NaN)
differs at CT vs RT; `-NaN and NaN have same bit representation
#499
Comments
I will check it. |
my gut feeling is that the problem is the magic proc |
see the generated C codes: NF a1;
NF a2;
a1 = NAN;
a2 = NAN; And JS codes var x1_369098755 = NaN;
var x2_369098756 = NaN;
var a1_369098757 = x1_369098755;
var a2_369098758 = x2_369098756; C backend generates NAN for NAN or -NAN, but VM doesn't. |
I think so. |
Unfortunately: import std/math
proc main =
let x1 = NaN
let x2 = -x1
let a1 = float64(x1)
let a2 = float64(x2)
doAssert isNaN(a1)
doAssert isNaN(a2)
echo cast[uint](a1)
echo cast[uint](a2)
static: main()
main() VM: So it may be called a bug. |
why close? the point of this issue is to track this bug; NaN should behave in CT like in RT, there are many numbers that are isNaN and each have their own (different) |
Sorry, I click the wrong button. |
The suspicious parts: of nkFloatLit, nkFloat64Lit:
result = rope(n.floatVal.toStrMaxPrecision)
of nkFloat32Lit:
result = rope(n.floatVal.toStrMaxPrecision("f")) |
So only float literals are handled in C/JS backend: proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
case classify(f)
of fcNan:
result = "NAN"
of fcNegZero:
result = "-0.0" & literalPostfix
of fcZero:
result = "0.0" & literalPostfix
of fcInf:
result = "INF"
of fcNegInf:
result = "-INF"
else:
result = newString(81)
let n = c_snprintf(result.cstring, result.len.uint, "%#.16e%s", f, literalPostfix.cstring)
setLen(result, n) |
What do you think of NaN literals and NaN exprs? Should them differ or not? Should let x = NaN
let y = -x vs let x = NaN
let y = -NaN |
let b = -NaN should give same result as: let a = NaN
let b = -a anything else makes no sense. proc identity[T](a: T): T =
result = a
proc main()=
let a = NaN
let b = -a
echo cast[uint](a) # ok
echo cast[uint](b) # ok
let c1 = -NaN
echo cast[uint](c1) # bug
let c = -(NaN)
echo cast[uint](c) # bug
let d = -identity(NaN)
echo cast[uint](d) # ok
main() 9221120237041090560 |
signbit should be able to solve this problem, though I'm not sure about JS backend. |
After a fix: import std/math
proc main =
let x1 = NaN
let x2 = -NaN
let x3 = -x1
doAssert isNaN(x1)
doAssert isNaN(x2)
doAssert isNaN(x3)
echo cast[uint](x1)
echo cast[uint](x2)
echo cast[uint](x3)
static: main()
main()
|
perfect! for js backend, |
note: good that it gives same results as python3 (and probably C, haven't checked but there's no reason it shouldn't work since ctypes is based on C): from math import nan
def fun(x):
print()
print(x)
import ctypes
u64 = ctypes.c_uint64.from_buffer(ctypes.c_double(x))
print(u64)
print(bin(u64.value))
fun(1.0)
fun(0.0)
fun(-0.0)
fun(nan)
fun(-nan)
|
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)
|
=> made it work here: nim-lang#16609 |
yeah, I mean JS backend also works(testing using signbit) |
this PR should defer until MY signbit PR is merged, then copySign could reuse parts of signbits. |
i agree, I've already LGTM'd nim-lang#16592, waiting for 2nd LGTM so we can merge it |
@xflywind looks like the problem is still there even after nim-lang#16628 is merged ... (PR is good but looks like we need something additional) |
Example
Current Output
CT:
9221120237041090559
18444492273895866367
RT:
9221120237041090560
9221120237041090560
Expected Output
cast[uint](a1)
vscast[uint](a2)
being the same, this seems odd; IMO we should just flip the sign bit regardless of NaN vs not NaN; we can also see what other langs doAdditional Information
devel 1.5.1
6d442a4
The text was updated successfully, but these errors were encountered: