Merge pull request #4245 from abudden/new-formateng
Modification to implementation of round() such that it returns a floa…
This commit is contained in:
commit
80f2e3ea00
4 changed files with 101 additions and 27 deletions
|
|
@ -489,7 +489,7 @@ proc leValueConv(a, b: PNode): bool =
|
||||||
of nkCharLit..nkUInt64Lit:
|
of nkCharLit..nkUInt64Lit:
|
||||||
case b.kind
|
case b.kind
|
||||||
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
|
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
|
||||||
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
|
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
|
||||||
else: internalError(a.info, "leValueConv")
|
else: internalError(a.info, "leValueConv")
|
||||||
of nkFloatLit..nkFloat128Lit:
|
of nkFloatLit..nkFloat128Lit:
|
||||||
case b.kind
|
case b.kind
|
||||||
|
|
|
||||||
|
|
@ -138,19 +138,10 @@ when not defined(JS):
|
||||||
proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
|
proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
|
||||||
## Computes the exponential function of `x` (pow(E, x))
|
## Computes the exponential function of `x` (pow(E, x))
|
||||||
|
|
||||||
proc frexp*(x: float32, exponent: var int): float32 {.
|
proc round0(x: float32): float32 {.importc: "roundf", header: "<math.h>".}
|
||||||
importc: "frexp", header: "<math.h>".}
|
proc round0(x: float64): float64 {.importc: "round", header: "<math.h>".}
|
||||||
proc frexp*(x: float64, exponent: var int): float64 {.
|
## Converts a float to an int by rounding. Used internally by the round
|
||||||
importc: "frexp", header: "<math.h>".}
|
## function when the specified number of places is 0.
|
||||||
## 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.
|
|
||||||
|
|
||||||
proc round*(x: float32): int {.importc: "lrintf", header: "<math.h>".}
|
|
||||||
proc round*(x: float64): int {.importc: "lrint", header: "<math.h>".}
|
|
||||||
## converts a float to an int by rounding.
|
|
||||||
|
|
||||||
proc arccos*(x: float32): float32 {.importc: "acosf", header: "<math.h>".}
|
proc arccos*(x: float32): float32 {.importc: "acosf", header: "<math.h>".}
|
||||||
proc arccos*(x: float64): float64 {.importc: "acos", header: "<math.h>".}
|
proc arccos*(x: float64): float64 {.importc: "acos", header: "<math.h>".}
|
||||||
|
|
@ -256,22 +247,11 @@ else:
|
||||||
|
|
||||||
proc exp*(x: float32): float32 {.importc: "Math.exp", nodecl.}
|
proc exp*(x: float32): float32 {.importc: "Math.exp", nodecl.}
|
||||||
proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.}
|
proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.}
|
||||||
proc round*(x: float): int {.importc: "Math.round", nodecl.}
|
proc round0(x: float): float {.importc: "Math.round", nodecl.}
|
||||||
|
|
||||||
proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.}
|
proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.}
|
||||||
proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.}
|
proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.}
|
||||||
|
|
||||||
proc 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 = floor(log2(x))
|
|
||||||
exponent = round(ex)
|
|
||||||
result = x / pow(2.0, ex)
|
|
||||||
|
|
||||||
proc arccos*(x: float32): float32 {.importc: "Math.acos", nodecl.}
|
proc arccos*(x: float32): float32 {.importc: "Math.acos", nodecl.}
|
||||||
proc arccos*(x: float64): float64 {.importc: "Math.acos", nodecl.}
|
proc arccos*(x: float64): float64 {.importc: "Math.acos", nodecl.}
|
||||||
proc arcsin*(x: float32): float32 {.importc: "Math.asin", nodecl.}
|
proc arcsin*(x: float32): float32 {.importc: "Math.asin", nodecl.}
|
||||||
|
|
@ -295,6 +275,60 @@ else:
|
||||||
var y = exp(2.0*x)
|
var y = exp(2.0*x)
|
||||||
return (y-1.0)/(y+1.0)
|
return (y-1.0)/(y+1.0)
|
||||||
|
|
||||||
|
proc round*[T: float32|float64](x: T, places: int = 0): T =
|
||||||
|
## Round a floating point number.
|
||||||
|
##
|
||||||
|
## If `places` is 0 (or omitted), round to the nearest integral value
|
||||||
|
## following normal mathematical rounding rules (e.g. `round(54.5) -> 55.0`).
|
||||||
|
## If `places` is greater than 0, round to the given number of decimal
|
||||||
|
## places, e.g. `round(54.346, 2) -> 54.35`.
|
||||||
|
## If `places` is negative, round to the left of the decimal place, e.g.
|
||||||
|
## `round(537.345, -1) -> 540.0`
|
||||||
|
if places == 0:
|
||||||
|
result = round0(x)
|
||||||
|
else:
|
||||||
|
var mult = pow(10.0, places.T)
|
||||||
|
result = round0(x*mult)/mult
|
||||||
|
|
||||||
|
when not defined(JS):
|
||||||
|
proc frexp*(x: float32, exponent: var int): float32 {.
|
||||||
|
importc: "frexp", header: "<math.h>".}
|
||||||
|
proc frexp*(x: float64, exponent: var int): float64 {.
|
||||||
|
importc: "frexp", header: "<math.h>".}
|
||||||
|
## 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.
|
||||||
|
else:
|
||||||
|
proc 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 = floor(log2(x))
|
||||||
|
exponent = round(ex)
|
||||||
|
result = x / pow(2.0, ex)
|
||||||
|
|
||||||
|
proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
|
||||||
|
## Breaks `x` into an integral and a fractional part.
|
||||||
|
##
|
||||||
|
## Returns a tuple containing intpart and floatpart representing
|
||||||
|
## the integer part and the fractional part respectively.
|
||||||
|
##
|
||||||
|
## Both parts have the same sign as `x`. Analogous to the `modf`
|
||||||
|
## function in C.
|
||||||
|
var
|
||||||
|
absolute: T
|
||||||
|
absolute = abs(x)
|
||||||
|
result.intpart = floor(absolute)
|
||||||
|
result.floatpart = absolute - result.intpart
|
||||||
|
if x < 0:
|
||||||
|
result.intpart = -result.intpart
|
||||||
|
result.floatpart = -result.floatpart
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc degToRad*[T: float32|float64](d: T): T {.inline.} =
|
proc degToRad*[T: float32|float64](d: T): T {.inline.} =
|
||||||
|
|
@ -357,3 +391,36 @@ when isMainModule and not defined(JS):
|
||||||
assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
|
assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
|
||||||
assert(erf(6.0) > erf(5.0))
|
assert(erf(6.0) > erf(5.0))
|
||||||
assert(erfc(6.0) < erfc(5.0))
|
assert(erfc(6.0) < erfc(5.0))
|
||||||
|
when isMainModule:
|
||||||
|
# Function for approximate comparison of floats
|
||||||
|
proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9)
|
||||||
|
|
||||||
|
block: # round() tests
|
||||||
|
# Round to 0 decimal places
|
||||||
|
doAssert round(54.652) ==~ 55.0
|
||||||
|
doAssert round(54.352) ==~ 54.0
|
||||||
|
doAssert round(-54.652) ==~ -55.0
|
||||||
|
doAssert round(-54.352) ==~ -54.0
|
||||||
|
doAssert round(0.0) ==~ 0.0
|
||||||
|
# Round to positive decimal places
|
||||||
|
doAssert round(-547.652, 1) ==~ -547.7
|
||||||
|
doAssert round(547.652, 1) ==~ 547.7
|
||||||
|
doAssert round(-547.652, 2) ==~ -547.65
|
||||||
|
doAssert round(547.652, 2) ==~ 547.65
|
||||||
|
# Round to negative decimal places
|
||||||
|
doAssert round(547.652, -1) ==~ 550.0
|
||||||
|
doAssert round(547.652, -2) ==~ 500.0
|
||||||
|
doAssert round(547.652, -3) ==~ 1000.0
|
||||||
|
doAssert round(547.652, -4) ==~ 0.0
|
||||||
|
doAssert round(-547.652, -1) ==~ -550.0
|
||||||
|
doAssert round(-547.652, -2) ==~ -500.0
|
||||||
|
doAssert round(-547.652, -3) ==~ -1000.0
|
||||||
|
doAssert round(-547.652, -4) ==~ 0.0
|
||||||
|
|
||||||
|
block: # splitDecimal() tests
|
||||||
|
doAssert splitDecimal(54.674).intpart ==~ 54.0
|
||||||
|
doAssert splitDecimal(54.674).floatpart ==~ 0.674
|
||||||
|
doAssert splitDecimal(-693.4356).intpart ==~ -693.0
|
||||||
|
doAssert splitDecimal(-693.4356).floatpart ==~ -0.4356
|
||||||
|
doAssert splitDecimal(0.0).intpart ==~ 0.0
|
||||||
|
doAssert splitDecimal(0.0).floatpart ==~ 0.0
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ template test(loopCount: int, extraI: int, testBody: stmt): stmt =
|
||||||
|
|
||||||
template test(loopCount: int, extraF: float, testBody: stmt): stmt =
|
template test(loopCount: int, extraF: float, testBody: stmt): stmt =
|
||||||
block:
|
block:
|
||||||
test(loopCount, round(extraF), testBody)
|
test(loopCount, round(extraF).int, testBody)
|
||||||
|
|
||||||
template test(loopCount: int, testBody: stmt): stmt =
|
template test(loopCount: int, testBody: stmt): stmt =
|
||||||
block:
|
block:
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,11 @@ Changes affecting backwards compatibility
|
||||||
- The path handling changed. The project directory is not added to the
|
- The path handling changed. The project directory is not added to the
|
||||||
search path automatically anymore. Add this line to your project's
|
search path automatically anymore. Add this line to your project's
|
||||||
config to get back the old behaviour: ``--path:"$projectdir"``.
|
config to get back the old behaviour: ``--path:"$projectdir"``.
|
||||||
|
- The ``round`` function in ``math.nim`` now returns a float and has been
|
||||||
|
corrected such that the C implementation always rounds up from .5 rather
|
||||||
|
than changing the operation for even and odd numbers.
|
||||||
|
- The ``round`` function now accepts a ``places`` argument to round to a
|
||||||
|
given number of places (e.g. round 4.35 to 4.4 if ``places`` is 1).
|
||||||
|
|
||||||
|
|
||||||
Library Additions
|
Library Additions
|
||||||
|
|
@ -56,6 +61,8 @@ Library Additions
|
||||||
- Added ``strscans`` module that implements a ``scanf`` for easy input extraction.
|
- Added ``strscans`` module that implements a ``scanf`` for easy input extraction.
|
||||||
- Added a version of ``parseutils.parseUntil`` that can deal with a string ``until`` token. The other
|
- Added a version of ``parseutils.parseUntil`` that can deal with a string ``until`` token. The other
|
||||||
versions are for ``char`` and ``set[char]``.
|
versions are for ``char`` and ``set[char]``.
|
||||||
|
- Added ``splitDecimal`` to ``math.nim`` to split a floating point value
|
||||||
|
into an integer part and a floating part (in the range -1<x<1).
|
||||||
|
|
||||||
|
|
||||||
Compiler Additions
|
Compiler Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue