From ded42d08eda1ce69cf9fb6f1a28198198ab48734 Mon Sep 17 00:00:00 2001 From: Gary Burgess Date: Thu, 16 Feb 2017 17:03:42 +0000 Subject: [PATCH] Fix `round`, `ceil`, `floor` for NaN / Infinity inputs --- bower.json | 3 ++- src/Data/Int.purs | 31 +++++++++++++++---------------- test/Test/Data/Int.purs | 17 ++++++++++++++--- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/bower.json b/bower.json index 1b29dd1..867ab86 100644 --- a/bower.json +++ b/bower.json @@ -17,8 +17,9 @@ "package.json" ], "dependencies": { - "purescript-maybe": "^2.0.0", + "purescript-globals": "^2.0.0", "purescript-math": "^2.0.0", + "purescript-maybe": "^2.0.0", "purescript-partial": "^1.1.2" }, "devDependencies": { diff --git a/src/Data/Int.purs b/src/Data/Int.purs index 1eb07d2..fdfef54 100644 --- a/src/Data/Int.purs +++ b/src/Data/Int.purs @@ -5,7 +5,7 @@ module Data.Int , round , toNumber , fromString - , Radix() + , Radix , radix , binary , octal @@ -19,19 +19,14 @@ module Data.Int , pow ) where -import Data.Boolean (otherwise) -import Data.BooleanAlgebra ((&&)) -import Data.Bounded (top, bottom) -import Data.Eq ((==), (/=)) -import Data.Function ((<<<)) +import Prelude + import Data.Int.Bits ((.&.)) -import Data.Maybe (Maybe(..), fromJust) -import Data.Ord ((<=), (>=)) +import Data.Maybe (Maybe(..), fromMaybe) +import Global (infinity) import Math as Math -import Partial.Unsafe (unsafePartial) - -- | Creates an `Int` from a `Number` value. The number must already be an -- | integer and fall within the valid range of values for the `Int` type -- | otherwise `Nothing` is returned. @@ -45,28 +40,32 @@ foreign import fromNumberImpl -> Maybe Int -- | Convert a `Number` to an `Int`, by taking the closest integer equal to or --- | less than the argument. Values outside the `Int` range are clamped. +-- | less than the argument. Values outside the `Int` range are clamped, `NaN` +-- | and `Infinity` values return 0. floor :: Number -> Int floor = unsafeClamp <<< Math.floor -- | Convert a `Number` to an `Int`, by taking the closest integer equal to or --- | greater than the argument. Values outside the `Int` range are clamped. +-- | greater than the argument. Values outside the `Int` range are clamped, +-- | `NaN` and `Infinity` values return 0. ceil :: Number -> Int ceil = unsafeClamp <<< Math.ceil -- | Convert a `Number` to an `Int`, by taking the nearest integer to the --- | argument. Values outside the `Int` range are clamped. +-- | argument. Values outside the `Int` range are clamped, `NaN` and `Infinity` +-- | values return 0. round :: Number -> Int round = unsafeClamp <<< Math.round -- | Convert an integral `Number` to an `Int`, by clamping to the `Int` range. --- | This function will throw an error at runtime if the argument is --- | non-integral. +-- | This function will return 0 if the input is `NaN` or an `Infinity`. unsafeClamp :: Number -> Int unsafeClamp x + | x == infinity = 0 + | x == -infinity = 0 | x >= toNumber top = top | x <= toNumber bottom = bottom - | otherwise = unsafePartial (fromJust (fromNumber x)) + | otherwise = fromMaybe 0 (fromNumber x) -- | Converts an `Int` value back into a `Number`. Any `Int` is a valid `Number` -- | so there is no loss of precision with this function. diff --git a/test/Test/Data/Int.purs b/test/Test/Data/Int.purs index c8d27b7..89a132b 100644 --- a/test/Test/Data/Int.purs +++ b/test/Test/Data/Int.purs @@ -5,10 +5,11 @@ import Prelude import Control.Monad.Eff (Eff) import Control.Monad.Eff.Console (CONSOLE, log) -import Data.Int (odd, even, fromString, floor, ceil, round, toNumber, - fromNumber, fromStringAs, binary, octal, hexadecimal, - radix, toStringAs, pow) +import Data.Int (odd, even, fromString, floor, ceil, round, toNumber, fromNumber, fromStringAs, binary, octal, hexadecimal, radix, toStringAs, pow) import Data.Maybe (Maybe(..), fromJust) + +import Global (nan, infinity) + import Partial.Unsafe (unsafePartial) import Test.Assert (ASSERT, assert) @@ -54,6 +55,16 @@ testInt = do testClamping ceil testClamping floor + + log "round, ceil, and floor should return 0 for NaN and Infinities" + let testNonNumber f = do + assert $ f nan == 0 + assert $ f infinity == 0 + + testNonNumber round + testNonNumber ceil + testNonNumber floor + log "fromString should read integers" assert $ fromString "0" == Just 0 assert $ fromString "9467" == Just 9467