Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Notable changes to this project are documented in this file. The format is based
## [Unreleased]

Breaking changes:
- Fix `signum zero` to return `zero` (#280 by @JordanMartinez)

New features:

Expand Down
12 changes: 9 additions & 3 deletions src/Data/Ord.purs
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,16 @@ between low hi x
abs :: forall a. Ord a => Ring a => a -> a
abs x = if x >= zero then x else negate x

-- | The sign function; always evaluates to either `one` or `negate one`. For
-- | any `x`, we should have `signum x * abs x == x`.
-- | The sign function; returns `one` if the argument is positive,
-- | `negate one` if the argument is negative, or `zero` if the argument is `zero`.
-- | For floating point numbers with signed zeroes, when called with a zero,
-- | this function returns the argument in order to preserve the sign.
-- | For any `x`, we should have `signum x * abs x == x`.
signum :: forall a. Ord a => Ring a => a -> a
signum x = if x >= zero then one else negate one
signum x =
if x < zero then negate one
else if x > zero then one
else x

-- | The `Ord1` type class represents totally ordered type constructors.
class Eq1 f <= Ord1 f where
Expand Down
6 changes: 6 additions & 0 deletions test/Test/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,9 @@ exports.testNumberShow = function(showNumber) {
]);
};
};

exports.objectIs = function(l) {
return function(r) {
return Object.is(l, r);
};
};
13 changes: 12 additions & 1 deletion test/Test/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Test.Main where

import Prelude
import Data.HeytingAlgebra (ff, tt, implies)
import Data.Ord (abs)
import Data.Ord (abs, signum)
import Test.Data.Generic.Rep (testGenericRep)
import Test.Utils (AlmostEff, assert)

Expand All @@ -15,6 +15,7 @@ main = do
testIntDegree
testRecordInstances
testGenericRep
testSignum

foreign import testNumberShow :: (Number -> String) -> AlmostEff

Expand Down Expand Up @@ -151,3 +152,13 @@ testRecordInstances = do
assert "Record top" $
(top :: { a :: Boolean }).a
== top

testSignum :: AlmostEff
testSignum = do
assert "signum positive zero" $ objectIs (signum 0.0) 0.0
assert "signum negative zero" $ objectIs (signum (-0.0)) (-0.0)

-- Seems to be only way to check whether zero is `-0.0` or `0.0`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot that our show doesn't distinguish negative and positive zero. But, you can still distinguish them without the FFI:

show (1.0/0.0) == "Infinity"
show (1.0/(-0.0)) == "-Infinity"

-- See "Case 2" in
-- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#using_object.is
foreign import objectIs :: Number -> Number -> Boolean