Skip to content
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

fix math.frexp function signature #16725

Merged
merged 19 commits into from
Feb 17, 2021
Merged
5 changes: 3 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,13 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
underlying code is also updated the same way.




- Added `math.signbit`.


- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably)

- Added `math.frexp` overload procs. Deprecate `c_frexp`, use `frexp` instead.

## Language changes

- `nimscript` now handles `except Exception as e`.
Expand Down
89 changes: 52 additions & 37 deletions lib/pure/math.nim
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ when defined(c) or defined(cpp):

proc c_signbit(x: SomeFloat): cint {.importc: "signbit", header: "<math.h>".}

func c_frexp*(x: cfloat, exponent: var cint): cfloat {.
importc: "frexpf", header: "<math.h>", deprecated: "Use `frexp` instead".}
func c_frexp*(x: cdouble, exponent: var cint): cdouble {.
importc: "frexp", header: "<math.h>", deprecated: "Use `frexp` instead".}

# don't export `c_frexp` in the future and remove `c_frexp2`.
func c_frexp2(x: cfloat, exponent: var cint): cfloat {.
importc: "frexpf", header: "<math.h>".}
func c_frexp2(x: cdouble, exponent: var cint): cdouble {.
importc: "frexp", header: "<math.h>".}
ringabout marked this conversation as resolved.
Show resolved Hide resolved

func binom*(n, k: int): int =
## Computes the `binomial coefficient <https://en.wikipedia.org/wiki/Binomial_coefficient>`_.
runnableExamples:
Expand Down Expand Up @@ -981,27 +992,48 @@ func euclMod*[T: SomeNumber](x, y: T): T {.since: (1, 5, 1).} =
if result < 0:
result += abs(y)

when not defined(js):
func c_frexp*(x: float32, exponent: var int32): float32 {.
importc: "frexp", header: "<math.h>".}
timotheecour marked this conversation as resolved.
Show resolved Hide resolved
func c_frexp*(x: float64, exponent: var int32): float64 {.
importc: "frexp", header: "<math.h>".}
func frexp*[T, U](x: T, exponent: var U): T =
ringabout marked this conversation as resolved.
Show resolved Hide resolved
## Split a number into mantissa and exponent.
##
## ``frexp`` calculates the mantissa m (a float greater than or equal to 0.5
## and less than 1) and the integer value n such that ``x`` (the original
## float value) equals ``m * 2**n``. frexp stores n in `exponent` and returns
## m.
##
runnableExamples:
var x: int
doAssert frexp(5.0, x) == 0.625
doAssert x == 3
var exp: int32
result = c_frexp(x, exp)
exponent = exp
func frexp[T: float32|float64](x: T): tuple[frac: T, exp: int] {.inline.} =
## Splits a number into mantissa and exponent.
## The mathematical formula for this method is: number = frac * 2 ^ exp.
ringabout marked this conversation as resolved.
Show resolved Hide resolved
when not defined(js):
var exp: cint
result.frac = c_frexp2(x, exp)
result.exp = exp
else:
if x == 0.0:
result = (0.0, 0)
ringabout marked this conversation as resolved.
Show resolved Hide resolved
elif x < 0.0:
result = frexp(-x)
result.frac = -result.frac
else:
var ex = trunc(log2(x))
result.exp = int(ex)
result.frac = x / pow(2.0, ex)
if abs(result.frac) >= 1:
inc(result.exp)
result.frac = result.frac / 2
if result.exp == 1024 and result.frac == 0.0:
result.frac = 0.99999999999999988898

since (1, 5, 1):
export frexp
ringabout marked this conversation as resolved.
Show resolved Hide resolved

func frexp*[T: float32|float64](x: T, exponent: var int): T {.inline.} =
## Splits a number into mantissa and exponent.
##
## `frexp` calculates the mantissa m (a float greater than or equal to 0.5
ringabout marked this conversation as resolved.
Show resolved Hide resolved
ringabout marked this conversation as resolved.
Show resolved Hide resolved
## and less than 1) and the integer value n such that `x` (the original
## float value) equals `m * 2**n`. frexp stores n in `exponent` and returns
## m.
##
runnableExamples:
var x: int
doAssert frexp(5.0, x) == 0.625
doAssert x == 3
(result, exponent) = frexp(x)

ringabout marked this conversation as resolved.
Show resolved Hide resolved

when not defined(js):
when windowsCC89:
# taken from Go-lang Math.Log2
const ln2 = 0.693147180559945309417232121458176568075500134360255254120680009
Expand Down Expand Up @@ -1035,23 +1067,6 @@ when not defined(js):
## echo log2(0.0) # -inf
## echo log2(-2.0) # nan

else:
func frexp*[T: float32|float64](x: T, exponent: var int): T =
if x == 0.0:
exponent = 0
result = 0.0
elif x < 0.0:
result = -frexp(-x, exponent)
else:
var ex = trunc(log2(x))
exponent = int(ex)
result = x / pow(2.0, ex)
if abs(result) >= 1:
inc(exponent)
result = result / 2
if exponent == 1024 and result == 0.0:
result = 0.99999999999999988898

func splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
## Breaks ``x`` into an integer and a fractional part.
##
Expand Down
6 changes: 3 additions & 3 deletions tests/stdlib/tfrexp1.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
discard """
targets: "js c cpp"
output: '''ok'''
"""

import math
import std/math

const manualTest = false

Expand Down Expand Up @@ -43,4 +42,5 @@ when manualTest:
else:
frexp_test(-200000.0, 200000.0, 0.125)

echo "ok"

doAssert frexp(8.0) == (0.5, 4)