-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add math.copySign #16406
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
Add math.copySign #16406
Changes from all commits
b77da8b
44a3295
62a250f
cfbddfe
7891b6c
cd1c38c
ac90382
7b4994e
2cafbc2
e1b4468
cfbe626
344a3e8
0e6ac7d
0b845d8
a3beedf
7280070
f8d5208
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,6 +62,9 @@ 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. | ||
|
||
proc c_copysign(x, y: cfloat): cfloat {.importc: "copysignf", header: "<math.h>".} | ||
proc c_copysign(x, y: cdouble): cdouble {.importc: "copysign", header: "<math.h>".} | ||
|
||
func binom*(n, k: int): int = | ||
## Computes the `binomial coefficient <https://en.wikipedia.org/wiki/Binomial_coefficient>`_. | ||
runnableExamples: | ||
|
@@ -153,6 +156,40 @@ func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} = | |
when defined(js): fn() | ||
else: result = c_isnan(x) | ||
|
||
func copySign*[T: SomeFloat](x, y: T): T {.inline, since: (1, 5, 1).} = | ||
ringabout marked this conversation as resolved.
Show resolved
Hide resolved
|
||
## Returns a value with the magnitude of `x` and the sign of `y`; | ||
## this works even if x or y are NaN or zero, both of which can carry a sign. | ||
runnableExamples: | ||
doAssert copySign(1.0, -0.0) == -1.0 | ||
doAssert copySign(0.0, -0.0) == -0.0 | ||
doAssert copySign(-1.0, 0.0) == 1.0 | ||
doAssert copySign(10.0, 0.0) == 10.0 | ||
|
||
doAssert copySign(Inf, -1.0) == -Inf | ||
doAssert copySign(-Inf, 1.0) == Inf | ||
doAssert copySign(-1.0, NaN) == 1.0 | ||
timotheecour marked this conversation as resolved.
Show resolved
Hide resolved
|
||
doAssert copySign(10.0, NaN) == 10.0 | ||
|
||
doAssert copySign(NaN, 0.0).isNaN | ||
doAssert copySign(NaN, -0.0).isNaN | ||
|
||
# fails in VM and JS backend | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it won't fail in VM for a nim binary compiled after your PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same story as #16406 (comment) |
||
doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 | ||
|
||
# TODO use signbit for examples | ||
template impl() = | ||
ringabout marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if y > 0.0 or (y == 0.0 and 1.0 / y > 0.0): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better code for js via Object.is, see #16505 (comment) |
||
result = abs(x) | ||
elif y <= 0.0: | ||
result = -abs(x) | ||
ringabout marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else: # must be NaN | ||
result = abs(x) | ||
|
||
when defined(js): impl() | ||
else: | ||
when nimvm: impl() | ||
else: result = c_copysign(x, y) | ||
|
||
func classify*(x: float): FloatClass = | ||
## Classifies a floating point value. | ||
## | ||
|
@@ -1159,3 +1196,4 @@ func lcm*[T](x: openArray[T]): T {.since: (1, 1).} = | |
while i < x.len: | ||
result = lcm(result, x[i]) | ||
inc(i) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -308,5 +308,53 @@ template main = | |
doAssert not Inf.isNaN | ||
doAssert isNaN(Inf - Inf) | ||
|
||
main() | ||
block: # copySign | ||
doAssert copySign(10.0, -1.0) == -10.0 | ||
doAssert copySign(-10.0, -1.0) == -10.0 | ||
doAssert copySign(-10.0, 1.0) == 10.0 | ||
doAssert copySign(float(10), -1.0) == -10.0 | ||
|
||
doAssert copySign(10.0'f64, -1.0) == -10.0 | ||
doAssert copySign(-10.0'f64, -1.0) == -10.0 | ||
doAssert copySign(-10.0'f64, 1.0) == 10.0 | ||
doAssert copySign(10'f64, -1.0) == -10.0 | ||
|
||
doAssert copySign(10.0'f32, -1.0) == -10.0 | ||
doAssert copySign(-10.0'f32, -1.0) == -10.0 | ||
doAssert copySign(-10.0'f32, 1.0) == 10.0 | ||
doAssert copySign(10'f32, -1.0) == -10.0 | ||
|
||
doAssert copySign(Inf, -1.0) == -Inf | ||
doAssert copySign(-Inf, 1.0) == Inf | ||
doAssert copySign(Inf, 1.0) == Inf | ||
doAssert copySign(-Inf, -1.0) == -Inf | ||
doAssert copySign(Inf, 0.0) == Inf | ||
doAssert copySign(Inf, -0.0) == -Inf | ||
doAssert copySign(-Inf, 0.0) == Inf | ||
doAssert copySign(-Inf, -0.0) == -Inf | ||
doAssert copySign(1.0, -0.0) == -1.0 | ||
doAssert copySign(0.0, -0.0) == -0.0 | ||
doAssert copySign(-1.0, 0.0) == 1.0 | ||
doAssert copySign(10.0, 0.0) == 10.0 | ||
doAssert copySign(-1.0, NaN) == 1.0 | ||
doAssert copySign(10.0, NaN) == 10.0 | ||
|
||
doAssert copySign(NaN, NaN).isNaN | ||
doAssert copySign(-NaN, NaN).isNaN | ||
doAssert copySign(NaN, -NaN).isNaN | ||
doAssert copySign(-NaN, -NaN).isNaN | ||
doAssert copySign(NaN, 0.0).isNaN | ||
doAssert copySign(NaN, -0.0).isNaN | ||
doAssert copySign(-NaN, 0.0).isNaN | ||
doAssert copySign(-NaN, -0.0).isNaN | ||
|
||
when nimvm: | ||
discard | ||
else: | ||
when not defined(js): | ||
doAssert copySign(-1.0, -NaN) == 1.0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. until timotheecour#499 is fixed, this test is meaningless: doAssert copySign(-1.0, -NaN) == 1.0
doAssert copySign(-1.0, NaN) == 1.0 both pass currently, which is not correct behavior IMO IMO when false: # xxx bug
doAssert copySign(-1.0, -NaN) == -1.0 likewise with |
||
doAssert copySign(10.0, -NaN) == 10.0 | ||
doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 # fails in VM | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this test actually works in VM so long nim is compiled after this PR. template fn() = doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0
when defined(js): discard # xxx bug
else:
when defined(nimHasCopySign): fn()
else:
when nimvm: discard
else: fn() (refs timotheecour#498) note, the same There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rather make a follow-up PR to enable this test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ya we definitely need this (in another PR as you say); refs timotheecour#494 (comment) ; it just requires a few disabling's for js to work (and vm already works) |
||
|
||
static: main() | ||
main() |
Uh oh!
There was an error while loading. Please reload this page.