Negative infinity and positive infinity have the same sign

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Negative infinity and positive infinity have the same sign

GLASS mailing list
On 3.3.0, "-0.0 sign = 0.0 sign". On Pharo, "-1 sign = -1", "-0.0 sign = -1", "0.0 sign = 0", and "1 sign = 1". IEEE Standard 754 mandates that negative zero have the same sign bit as a negative number.
_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: Negative infinity and positive infinity have the same sign

GLASS mailing list
Thanks Monty, I've submitted internal bug #46646 "Negative infinity and
positive infinity have the same sign (IEEE Standard 754)".

If you need a patch, the following topaz script should help:

method: Float
sign
| s |
s := self _sign .
self = 0.0 ifTrue:[ s == 1 ifTrue:[ ^ 0]].
^ s
%

Dale

On 01/25/2017 12:45 PM, monty via Glass wrote:
> On 3.3.0, "-0.0 sign = 0.0 sign". On Pharo, "-1 sign = -1", "-0.0 sign = -1", "0.0 sign = 0", and "1 sign = 1". IEEE Standard 754 mandates that negative zero have the same sign bit as a negative number.
> _______________________________________________
> Glass mailing list
> [hidden email]
> http://lists.gemtalksystems.com/mailman/listinfo/glass

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: Negative infinity and positive infinity have the same sign

GLASS mailing list
In reply to this post by GLASS mailing list
On 01/25/2017 12:45 PM, monty via Glass wrote:
> On 3.3.0, "-0.0 sign = 0.0 sign". On Pharo, "-1 sign = -1", "-0.0 sign = -1", "0.0 sign = 0", and "1 sign = 1". IEEE Standard 754 mandates that negative zero have the same sign bit as a negative number.
> _______________________________________________
Hi Monty,

The ANSI Smalltalk standard says that #sign should answer 0 if "the
receiver equals zero". This agrees with ISO/IEC 10967 Portable Numerics
standard, which says the same thing. The IEEE 754 spec does not specify
a "sign" operation. The closest equivalent I see is the "isSignMinus"
operation. We don't currently have that message in GemStone, but we
might add it. In GemStone, you can distinguish positive and negative
zero by sending #_sign.

Pharo's implementation seems very odd. It looks like it's been that way
a long time (John Maloney in 1998?) but the comment contradicts itself.
It says
"Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0.
    Handle IEEE-754 negative-zero by reporting a sign of -1"

But negative zero *is* equal to 0, so it claims to be answering both 0
and -1 for -0.0. Leaving that aside, it's disturbingly asymmetric to
answer 0 for 0.0 but -1 for -0.0.

Regards,

-Martin
_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: Negative infinity and positive infinity have the same sign

GLASS mailing list
Looks like you're correct; Pharo has the bug, not GS. All I really wanted was to distinguish +/- 0, so your fix will do. But be aware that ANSI Smalltalk also defines #negated in terms of ISO 10967's 'neg', which returns -0.0 for 0.0 and 0.0 for -1.0, so #sign or other such disparities between +/- 0 are not obviously wrong.

> Sent: Thursday, January 26, 2017 at 3:10 PM
> From: "Martin McClure" <[hidden email]>
> To: monty <[hidden email]>, [hidden email]
> Subject: Re: [Glass] Negative infinity and positive infinity have the same sign
>
> On 01/25/2017 12:45 PM, monty via Glass wrote:
> > On 3.3.0, "-0.0 sign = 0.0 sign". On Pharo, "-1 sign = -1", "-0.0 sign = -1", "0.0 sign = 0", and "1 sign = 1". IEEE Standard 754 mandates that negative zero have the same sign bit as a negative number.
> > _______________________________________________
> Hi Monty,
>
> The ANSI Smalltalk standard says that #sign should answer 0 if "the
> receiver equals zero". This agrees with ISO/IEC 10967 Portable Numerics
> standard, which says the same thing. The IEEE 754 spec does not specify
> a "sign" operation. The closest equivalent I see is the "isSignMinus"
> operation. We don't currently have that message in GemStone, but we
> might add it. In GemStone, you can distinguish positive and negative
> zero by sending #_sign.
>
> Pharo's implementation seems very odd. It looks like it's been that way
> a long time (John Maloney in 1998?) but the comment contradicts itself.
> It says
> "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0.
>     Handle IEEE-754 negative-zero by reporting a sign of -1"
>
> But negative zero *is* equal to 0, so it claims to be answering both 0
> and -1 for -0.0. Leaving that aside, it's disturbingly asymmetric to
> answer 0 for 0.0 but -1 for -0.0.
>
> Regards,
>
> -Martin
>
_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: Negative infinity and positive infinity have the same sign

GLASS mailing list
On 01/26/2017 06:16 PM, monty via Glass wrote:
> Looks like you're correct; Pharo has the bug, not GS. All I really wanted was to distinguish +/- 0, so your fix will do. But be aware that ANSI Smalltalk also defines #negated in terms of ISO 10967's 'neg', which returns -0.0 for 0.0 and 0.0 for -1.0, so #sign or other such disparities between +/- 0 are not obviously wrong.
>
I agree, and we do handle #negated correctly, AFAICT. We welcome reports
if you find any place where we do not do things correctly -- we made an
effort to clean up the finer points of numerics several years ago, but
it's always possible we missed something.

Regards,

-Martin

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: Negative infinity and positive infinity have the same sign

GLASS mailing list
In reply to this post by GLASS mailing list
Apparently there is also #signBit, which works for SmallFloats too, and because SmallDouble is immediate, you can also use #== with -0.0 after sending #asFloat (to convert non-floats, SmallFloats, and DecimalFloats).

The only backwards compatible approach I found for Pharo/Squeak is to use #at: on a zero float to test if its first (big-endian) word is non-zero.

> Sent: Thursday, January 26, 2017 at 3:10 PM
> From: "Martin McClure" <[hidden email]>
> To: monty <[hidden email]>, [hidden email]
> Subject: Re: [Glass] Negative infinity and positive infinity have the same sign
>
> On 01/25/2017 12:45 PM, monty via Glass wrote:
> > On 3.3.0, "-0.0 sign = 0.0 sign". On Pharo, "-1 sign = -1", "-0.0 sign = -1", "0.0 sign = 0", and "1 sign = 1". IEEE Standard 754 mandates that negative zero have the same sign bit as a negative number.
> > _______________________________________________
> Hi Monty,
>
> The ANSI Smalltalk standard says that #sign should answer 0 if "the
> receiver equals zero". This agrees with ISO/IEC 10967 Portable Numerics
> standard, which says the same thing. The IEEE 754 spec does not specify
> a "sign" operation. The closest equivalent I see is the "isSignMinus"
> operation. We don't currently have that message in GemStone, but we
> might add it. In GemStone, you can distinguish positive and negative
> zero by sending #_sign.
>
> Pharo's implementation seems very odd. It looks like it's been that way
> a long time (John Maloney in 1998?) but the comment contradicts itself.
> It says
> "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0.
>     Handle IEEE-754 negative-zero by reporting a sign of -1"
>
> But negative zero *is* equal to 0, so it claims to be answering both 0
> and -1 for -0.0. Leaving that aside, it's disturbingly asymmetric to
> answer 0 for 0.0 but -1 for -0.0.
>
> Regards,
>
> -Martin
>
_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: Negative infinity and positive infinity have the same sign

GLASS mailing list
In reply to this post by GLASS mailing list
Thanks Dale and Martin for your help.
_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: Negative infinity and positive infinity have the same sign

GLASS mailing list
On 01/27/2017 10:51 AM, monty via Glass wrote:
> Thanks Dale and Martin for your help.

You're welcome!

-Martin

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: Negative infinity and positive infinity have the same sign

GLASS mailing list
Hi All,

I brought this up to squeak-dev, as this bug happens in Squeak, too.

Here is what Nicolas Cellier just pushed to Squeak Trunk, hope that helps.

Begin forwarded message:

> From: [hidden email]
> Subject: [squeak-dev] The Trunk: Kernel-nice.1054.mcz
> Date: 27. Januar 2017 21:45:16 MEZ
> To: [hidden email], [hidden email]
> Reply-To: [hidden email]
> Delivered-To: [hidden email]
>
> Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
> http://source.squeak.org/trunk/Kernel-nice.1054.mcz
>
> ==================== Summary ====================
>
> Name: Kernel-nice.1054
> Author: nice
> Time: 27 January 2017, 9:44:46.83377 pm
> UUID: ef21d74d-ba81-47c6-9bb7-92fb4140f494
> Ancestors: Kernel-eem.1053
>
> Change -0.0 sign to answer 0 instead of -1.
> Introduce a new message signBit for recognition of Float negativeZero.
>
> Rationale:
> 1) The value of Float negativeZero cannot be distinguished from zero.
>   Thus (Float negativeZero = 0.0)
>   We can then expect sign to be symmetric for (positive) zero and negativeZero
> 2) ANSI Smalltalk requires above behavior.
>   This will reduce un-necessary difference with Gemstone for example.
>
> About NaN:
> Note that with old implementation, the sign of "positive" nan was 0, while it was -1 for "negative" nan.
> New implementation will allways answer 0 for nans.
>
> We may as well answer Float nan, but currently sign will allways answer an Integer (-1,0 or 1). Until it is well specified by a standard, let's not bother.
> Otherwise, we could answer a Float if receiver is a Float like:
>
> sign
> self > 0.0 ifTrue: [ ^1.0].
> self < 0.0 ifTrue: [ ^-1.0].
> ^self
>
> =============== Diff against Kernel-eem.1053 ===============
>
> Item was changed:
>  ----- Method: Float>>arcTan: (in category 'mathematical functions') -----
>  arcTan: denominator
> + "Answer the angle in radians, taking care of 4 quadrants.
> + Implementation note: use signBit and sign: in order to catch cases of negativeZero"
> - "Answer the angle in radians.
> - Optional. See Object documentation whatIsAPrimitive.
> - Implementation note: use sign in order to catch cases of negativeZero"
>
> + self = 0.0
> + ifTrue:
> + [denominator signBit = 0 ifTrue: [ ^0.0 ].
> + ^Pi sign: self ].
> + denominator = 0.0 ifTrue: [ ^Halfpi sign: self ].
> + denominator > 0.0 ifTrue: [ ^(self / denominator) arcTan ].
> + ^(self / denominator) arcTan + (Pi sign: self)!
> - self = 0.0 ifTrue: [
> - denominator sign >= 0 ifTrue: [ ^0.0 ].
> - self sign >= 0 ifTrue: [ ^Pi ].
> - ^0.0 - Pi ].
> - denominator = 0.0 ifTrue: [
> - self > 0.0 ifTrue: [ ^Halfpi ].
> - ^0.0 - Halfpi ].
> - denominator > 0.0 ifTrue: [  ^(self / denominator) arcTan ].
> - self > 0.0 ifTrue: [ ^(self / denominator) arcTan + Pi ].
> - ^(self / denominator) arcTan - Pi!
>
> Item was changed:
>  ----- Method: Float>>byteEncode:base: (in category 'printing') -----
>  byteEncode: aStream base: base
>   "Handle sign, zero, and NaNs; all other values passed to absPrintOn:base:"
>
>   self isNaN ifTrue: [aStream print: 'NaN'. ^ self]. "check for NaN before sign"
>   self > 0.0
>   ifTrue: [self absByteEncode: aStream base: base]
>   ifFalse:
> + [self signBit = 1
> - [self sign = -1
>   ifTrue: [aStream print: '-'].
>   self = 0.0
>   ifTrue: [aStream print: '0.0'. ^ self]
>   ifFalse: [aStream writeNumber:self negated base: base]]!
>
> Item was removed:
> - ----- Method: Float>>copySignTo: (in category 'mathematical functions') -----
> - copySignTo: aNumber
> - "Return a number with same magnitude as aNumber and same sign as self.
> - Implementation note: take care of Float negativeZero, which is considered as having a negative sign."
> -
> - (self > 0.0 or: [(self at: 1) = 0]) ifTrue: [^ aNumber abs].
> - ^aNumber withNegativeSign!
>
> Item was changed:
>  ----- Method: Float>>printOn:base: (in category 'printing') -----
>  printOn: aStream base: base
>   "Print the receiver with the minimal number of digits that describes it unambiguously.
>   This way, every two different Float will have a different printed representation.
>   More over, every Float can be reconstructed from its printed representation with #readFrom:."
>
>   self isNaN ifTrue: [aStream nextPutAll: 'NaN'. ^ self]. "check for NaN before sign"
>   self > 0.0
>   ifTrue: [self absPrintExactlyOn: aStream base: base]
>   ifFalse:
> + [self signBit = 1
> - [self sign = -1
>   ifTrue: [aStream nextPutAll: '-'].
>   self = 0.0
>   ifTrue: [aStream nextPutAll: '0.0']
>   ifFalse: [self negated absPrintExactlyOn: aStream base: base]]!
>
> Item was changed:
>  ----- Method: Float>>printOn:maxDecimalPlaces: (in category 'printing') -----
>  printOn: aStream maxDecimalPlaces: placesDesired
>   "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:"
>  
>   self isFinite ifFalse: [^self printOn: aStream].
>   self > 0.0
>   ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false]
>   ifFalse:
> + [self signBit = 1
> - [self sign = -1
>   ifTrue: [aStream nextPutAll: '-'].
>   self = 0.0
>   ifTrue: [aStream nextPutAll: '0.0']
>   ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false]]!
>
> Item was changed:
>  ----- Method: Float>>printOn:showingDecimalPlaces: (in category 'printing') -----
>  printOn: aStream showingDecimalPlaces: placesDesired
>   "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:"
>  
>   self isFinite ifFalse: [^self printOn: aStream].
>   self > 0.0
>   ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true]
>   ifFalse:
> + [self signBit = 1
> - [self sign = -1
>   ifTrue: [aStream nextPutAll: '-'].
>   self = 0.0
>   ifTrue:
>   [aStream nextPut: $0.
>   placesDesired > 0 ifTrue: [aStream nextPut: $.; next: placesDesired put: $0]]
>   ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true]]!
>
> Item was removed:
> - ----- Method: Float>>sign (in category 'mathematical functions') -----
> - sign
> - "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0.
> - Handle IEEE-754 negative-zero by reporting a sign of -1"
> -
> - self > 0.0 ifTrue: [ ^1 ].
> - self < 0.0 ifTrue: [ ^-1 ].
> - ^0 - ((self at: 1) bitShift: -31) "-1 for negative zero, 0 otherwise"!
>
> Item was removed:
> - ----- Method: Float>>sign: (in category 'mathematical functions') -----
> - sign: aNumber
> - "Return a Number with the same sign as aNumber and same magnitude as self.
> - Implementation is different from super to handle the special case of Float negativeZero."
> -
> - (self = 0.0 and: [aNumber sign negative]) ifTrue: [^Float negativeZero].
> - ^aNumber copySignTo: self!
>
> Item was added:
> + ----- Method: Float>>signBit (in category 'mathematical functions') -----
> + signBit
> + "Answer 1 if the receiver has sign bit set (including case of IEEE-754 negative-zero).
> + Answer 0 otherwise"
> +
> + ^((self at: 1) bitShift: -31)!
>
> Item was changed:
>  ----- Method: Float>>storeOn:base: (in category 'printing') -----
>  storeOn: aStream base: base
>   "Print the Number exactly so it can be interpreted back unchanged"
>   self isFinite
> + ifTrue: [self signBit = 1 ifTrue: [aStream nextPutAll: '-'].
> - ifTrue: [self sign = -1 ifTrue: [aStream nextPutAll: '-'].
>   base = 10 ifFalse: [aStream print: base; nextPut: $r].
>   self = 0.0
>   ifTrue: [aStream nextPutAll: '0.0']
>   ifFalse: [self abs absPrintExactlyOn: aStream base: base]]
>   ifFalse: [self isNaN
>   ifTrue: [aStream nextPutAll: 'Float nan']
>   ifFalse: [self > 0.0
>   ifTrue: [aStream nextPutAll: 'Float infinity']
>   ifFalse: [aStream nextPutAll: 'Float infinity negated']]]!
>
> Item was removed:
> - ----- Method: Float>>withNegativeSign (in category 'converting') -----
> - withNegativeSign
> - "Same as super, but handle the subtle case of Float negativeZero"
> -
> - self = 0.0 ifTrue: [^self class negativeZero].  
> - ^super withNegativeSign!
>
> Item was added:
> + ----- Method: LargeNegativeInteger>>signBit (in category 'testing') -----
> + signBit
> + "Optimization."
> +
> + ^1
> + !
>
> Item was added:
> + ----- Method: LargePositiveInteger>>signBit (in category 'testing') -----
> + signBit
> + "Optimization."
> +
> + ^0!
>
> Item was changed:
>  ----- Method: Number>>copySignTo: (in category 'mathematical functions') -----
>  copySignTo: aNumber
>   "Return a number with same magnitude as aNumber and same sign as self."
>
> + ^ self signBit = 0
> - ^ self positive
>   ifTrue: [aNumber abs]
> + ifFalse: [aNumber abs negated].!
> - ifFalse: [aNumber withNegativeSign].!
>
> Item was added:
> + ----- Method: Number>>signBit (in category 'mathematical functions') -----
> + signBit
> + "Answer 1 if the receiver is negative, zero otherwise."
> +
> + self < 0 ifTrue: [^1].
> + ^0!
>
> Item was removed:
> - ----- Method: Number>>withNegativeSign (in category 'converting') -----
> - withNegativeSign
> - "Answer a number with same magnitude than receiver and negative sign."
> - ^self abs negated!
>
>


On 27.01.2017, at 19:56, Martin McClure via Glass <[hidden email]> wrote:

> On 01/27/2017 10:51 AM, monty via Glass wrote:
>> Thanks Dale and Martin for your help.
>
> You're welcome!
>
> -Martin
>
> _______________________________________________
> Glass mailing list
> [hidden email]
> http://lists.gemtalksystems.com/mailman/listinfo/glass

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass