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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |