Hello. I found interesting thing: Why it is like this? Best regards, Natalia
:) in Smalltalk, the division of two integers is a fraction, not a float. i.e. 1/5 is 1/5. Thierry Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #= But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic. Regards! Esteban A. Maringolo 2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
Thatâs why mathematics and programming are two different things⦠On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal. On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote:
Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
On 11 Jul 2014, at 16:22, kilon alios <kilon.alios@gmail.com> wrote:
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal.
because it wouldnât be correct :)
On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote: Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
On 11 Jul 2014, at 16:30, Esteban Lorenzano <estebanlm@gmail.com> wrote:
On 11 Jul 2014, at 16:22, kilon alios <kilon.alios@gmail.com> wrote:
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal.
because it wouldnât be correct :)
But then why 4/2 = 2?
On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote: Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
Am 11.07.2014 um 16:33 schrieb Yuriy Tymchuk <yuriy.tymchuk@me.com>:
On 11 Jul 2014, at 16:30, Esteban Lorenzano <estebanlm@gmail.com> wrote:
On 11 Jul 2014, at 16:22, kilon alios <kilon.alios@gmail.com> wrote:
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal.
because it wouldnât be correct :)
But then why 4/2 = 2?
The same reason why 4/3 = 8/6 :) Norbert
On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote: Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
I would put it this way: - If you writing code, which requires comparing two floating-point values for equality, then you do something wrong. -- Best regards, Igor Stasenko.
On 11 juil. 2014, at 17:01, Igor Stasenko <siguctua@gmail.com> wrote:
I would put it this way: - If you writing code, which requires comparing two floating-point values for equality, then you do something wrong.
:D Rule of thumb: don't use floats ;)
-- Best regards, Igor Stasenko.
But why 185/10 = 18.5 -> true? On Jul 11, 2014, at 4:40 PM, Norbert Hartl <norbert@hartl.name> wrote:
Am 11.07.2014 um 16:33 schrieb Yuriy Tymchuk <yuriy.tymchuk@me.com>:
On 11 Jul 2014, at 16:30, Esteban Lorenzano <estebanlm@gmail.com> wrote:
On 11 Jul 2014, at 16:22, kilon alios <kilon.alios@gmail.com> wrote:
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal.
because it wouldnât be correct :)
But then why 4/2 = 2?
The same reason why
4/3 = 8/6
:)
Norbert
On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote: Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
Hi Natalia, The major problem comes from float memory representation. You can read the beginning of chapter "Fun with Floats" of Deep into Pharo that gives examples of why comparing floats is dangerous. http://rmod.lille.inria.fr/deepIntoPharo/ #Luc 2014-07-11 17:02 GMT+02:00 Natalia Tymchuk <natalia.tymchuk@unikernel.net>:
But why 185/10 = 18.5 -> true?
On Jul 11, 2014, at 4:40 PM, Norbert Hartl <norbert@hartl.name> wrote:
Am 11.07.2014 um 16:33 schrieb Yuriy Tymchuk <yuriy.tymchuk@me.com>:
On 11 Jul 2014, at 16:30, Esteban Lorenzano <estebanlm@gmail.com> wrote:
On 11 Jul 2014, at 16:22, kilon alios <kilon.alios@gmail.com> wrote:
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal.
because it wouldnât be correct :)
But then why 4/2 = 2?
The same reason why
4/3 = 8/6
:)
Norbert
On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote:
Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
On 11 juil. 2014, at 17:02, Natalia Tymchuk <natalia.tymchuk@unikernel.net> wrote:
But why 185/10 = 18.5 -> true?
Because 18.5 has an exact float representation, while 0.2 hasn't. Couldn't we use #asApproximateFraction instead of #asTrueFraction in Float>>adaptToFraction:andCompare: ? 0.2 asApproximateFraction ==> (1/5) 0.2 asTrueFraction ==> (3602879701896397/18014398509481984)
On Jul 11, 2014, at 4:40 PM, Norbert Hartl <norbert@hartl.name> wrote:
Am 11.07.2014 um 16:33 schrieb Yuriy Tymchuk <yuriy.tymchuk@me.com>:
On 11 Jul 2014, at 16:30, Esteban Lorenzano <estebanlm@gmail.com> wrote:
On 11 Jul 2014, at 16:22, kilon alios <kilon.alios@gmail.com> wrote:
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal.
because it wouldnât be correct :)
But then why 4/2 = 2?
The same reason why
4/3 = 8/6
:)
Norbert
On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote: Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
Thanks all of you. Best regards, Natalia On Jul 11, 2014, at 5:14 PM, Camille Teruel <camille.teruel@gmail.com> wrote:
On 11 juil. 2014, at 17:02, Natalia Tymchuk <natalia.tymchuk@unikernel.net> wrote:
But why 185/10 = 18.5 -> true?
Because 18.5 has an exact float representation, while 0.2 hasn't.
Couldn't we use #asApproximateFraction instead of #asTrueFraction in Float>>adaptToFraction:andCompare: ? 0.2 asApproximateFraction ==> (1/5) 0.2 asTrueFraction ==> (3602879701896397/18014398509481984)
On Jul 11, 2014, at 4:40 PM, Norbert Hartl <norbert@hartl.name> wrote:
Am 11.07.2014 um 16:33 schrieb Yuriy Tymchuk <yuriy.tymchuk@me.com>:
On 11 Jul 2014, at 16:30, Esteban Lorenzano <estebanlm@gmail.com> wrote:
On 11 Jul 2014, at 16:22, kilon alios <kilon.alios@gmail.com> wrote:
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal.
because it wouldnât be correct :)
But then why 4/2 = 2?
The same reason why
4/3 = 8/6
:)
Norbert
On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote: Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
2014-07-11 17:14 GMT+02:00 Camille Teruel <camille.teruel@gmail.com>:
On 11 juil. 2014, at 17:02, Natalia Tymchuk <natalia.tymchuk@unikernel.net> wrote:
But why 185/10 = 18.5 -> true?
Because 18.5 has an exact float representation, while 0.2 hasn't.
Couldn't we use #asApproximateFraction instead of #asTrueFraction in Float>>adaptToFraction:andCompare: ?
No, it would be a bad thing. For example, it would break the fact that = should be an equivalence relation (a=b && (b=c) ==> (a=c)). See for example http://bugs.squeak.org/view.php?id=3374 for a genesis of this feature. And note that lispers have preceded us by many years.
0.2 asApproximateFraction ==> (1/5) 0.2 asTrueFraction ==> (3602879701896397/18014398509481984)
There is also asMinimalDecimalFraction or something like that.
On Jul 11, 2014, at 4:40 PM, Norbert Hartl <norbert@hartl.name> wrote:
Am 11.07.2014 um 16:33 schrieb Yuriy Tymchuk <yuriy.tymchuk@me.com>:
On 11 Jul 2014, at 16:30, Esteban Lorenzano <estebanlm@gmail.com> wrote:
On 11 Jul 2014, at 16:22, kilon alios <kilon.alios@gmail.com> wrote:
why not round it before comparing it ? looks like an easy enough problem to fix . I would expect that to be equal.
because it wouldnât be correct :)
But then why 4/2 = 2?
The same reason why
4/3 = 8/6
:)
Norbert
On Fri, Jul 11, 2014 at 5:18 PM, Yuriy Tymchuk <yuriy.tymchuk@me.com> wrote:
Thatâs why mathematics and programming are two different thingsâ¦
On 11 Jul 2014, at 16:08, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
Usually comparing against floats is not as deterministic as you would expect. And in other dialects you use #equals: instead of #=
But in Pharo there is no #equals: and instead there is a #closeTo:, but #closeTo: has an arbitrary decimal precision, more than enough for commong arithmetic.
Regards!
Esteban A. Maringolo
2014-07-11 10:59 GMT-03:00 Goubier Thierry <thierry.goubier@cea.fr>:
:)
in Smalltalk, the division of two integers is a fraction, not a float.
i.e. 1/5 is 1/5.
Thierry
Le 11/07/2014 15:53, Natalia Tymchuk a écrit :
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
-- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_... On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
2014-07-12 0:40 GMT+02:00 Andres Valloud <avalloud@smalltalk.comcastbiz.net> :
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before: {1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false). IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base. I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected). That's allways what made me favour casual equality to universal inequality. Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history... Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before:
{1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false).
IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base.
IME, that's because loose code appears to work. What enables that loose code to work is the loose mixed mode arithmetic. I could understand integers and fractions. Adding floating point to the mix stops making as much sense to me. Equality between floating point numbers does make sense. Equality between floating point numbers and scaled decimals or fractions... in general, I don't see how they could make sense. I'd rather see the scaled decimals and fractions explicitly converted to floating point numbers, following a well defined procedure, and then compared... Andres.
I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected).
That's allways what made me favour casual equality to universal inequality.
Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history...
Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
2014-07-12 1:29 GMT+02:00 Andres Valloud <avalloud@smalltalk.comcastbiz.net> :
I don't think it makes sense to compare floating point numbers to
other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before:
{1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false).
IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base.
IME, that's because loose code appears to work. What enables that loose code to work is the loose mixed mode arithmetic. I could understand integers and fractions. Adding floating point to the mix stops making as much sense to me.
Equality between floating point numbers does make sense. Equality between floating point numbers and scaled decimals or fractions... in general, I don't see how they could make sense. I'd rather see the scaled decimals and fractions explicitly converted to floating point numbers, following a well defined procedure, and then compared...
Andres.
Why do such mixed arithmetic comparisons make sense? Maybe we used floating points in some low level Graphics for optimization reasons. After these optimized operations we get a Float result by contagion, but our intention is still to handle Numbers. It would be possible to riddle the code with explicit asFloat/asFraction conversions, but that does not feel like a superior solution... OK, we can as well convert to inexact first before comparing for this purpose. That's what C does, because C is too low level to ever care of transitivity and equivalence relationship. It's not even safe in C because the compiler can decide to promote to a larger precision behind your back... But let's ignore this "feature" and see what lispers recommend instead: http://www.lispworks.com/documentation/lcl50/aug/aug-170.html It says: In general, when an operation involves both a rational and a floating-point argument, the rational number is first converted to floating-point format, and then the operation is performed. This conversion process is called *floating-point contagion* <http://www.lispworks.com/reference/lcl50/aug/aug-193.html#MARKER-9-47>. However, for numerical equality comparisons, the arguments are compared using rational arithmetic to ensure transitivity of the equality (or inequality) relation. So my POV is not very new, it's an old thing. It's also a well defined procedure, and somehow better to my taste because it preserve more mathematical properties. If Smalltalk wants to be a better Lisp, maybe it should not constantly ignore Lisp wisdom ;) We can of course argue about the utility of transitivity... As a general library we provide tools like Dictionary that rely on transitivity. You can't tell how those Dictionary will be used in real applications, so my rule of thumb is the principle of least astonishment. I've got bitten once by such transitivity while memoizing... I switched to a better strategy with double indirection as workaround: class -> value -> result, but it was surprising.
I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such
a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected).
That's allways what made me favour casual equality to universal inequality.
Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history...
Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
In short, my point is that if one is going to "optimize" using floating point, then be thorough. If everything is a float, then conversion isn't a problem, comparison isn't a problem, etc. Starting from a more consistent place makes painful contortions unnecessary. On 7/11/14 17:19 , Nicolas Cellier wrote:
2014-07-12 1:29 GMT+02:00 Andres Valloud <avalloud@smalltalk.comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net>>:
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before:
{1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false).
IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base.
IME, that's because loose code appears to work. What enables that loose code to work is the loose mixed mode arithmetic. I could understand integers and fractions. Adding floating point to the mix stops making as much sense to me.
Equality between floating point numbers does make sense. Equality between floating point numbers and scaled decimals or fractions... in general, I don't see how they could make sense. I'd rather see the scaled decimals and fractions explicitly converted to floating point numbers, following a well defined procedure, and then compared...
Andres.
Why do such mixed arithmetic comparisons make sense? Maybe we used floating points in some low level Graphics for optimization reasons. After these optimized operations we get a Float result by contagion, but our intention is still to handle Numbers. It would be possible to riddle the code with explicit asFloat/asFraction conversions, but that does not feel like a superior solution...
OK, we can as well convert to inexact first before comparing for this purpose. That's what C does, because C is too low level to ever care of transitivity and equivalence relationship. It's not even safe in C because the compiler can decide to promote to a larger precision behind your back... But let's ignore this "feature" and see what lispers recommend instead:
http://www.lispworks.com/documentation/lcl50/aug/aug-170.html
It says:
In general, when an operation involves both a rational and a floating-point argument, the rational number is first converted to floating-point format, and then the operation is performed. This conversion process is called /floating-point contagion/ <http://www.lispworks.com/reference/lcl50/aug/aug-193.html#MARKER-9-47>. However, for numerical equality comparisons, the arguments are compared using rational arithmetic to ensure transitivity of the equality (or inequality) relation.
So my POV is not very new, it's an old thing. It's also a well defined procedure, and somehow better to my taste because it preserve more mathematical properties. If Smalltalk wants to be a better Lisp, maybe it should not constantly ignore Lisp wisdom ;)
We can of course argue about the utility of transitivity... As a general library we provide tools like Dictionary that rely on transitivity. You can't tell how those Dictionary will be used in real applications, so my rule of thumb is the principle of least astonishment. I've got bitten once by such transitivity while memoizing... I switched to a better strategy with double indirection as workaround: class -> value -> result, but it was surprising.
I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected).
That's allways what made me favour casual equality to universal inequality.
Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history...
Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
2014-07-12 2:26 GMT+02:00 Andres Valloud <avalloud@smalltalk.comcastbiz.net> :
In short, my point is that if one is going to "optimize" using floating point, then be thorough. If everything is a float, then conversion isn't a problem, comparison isn't a problem, etc. Starting from a more consistent place makes painful contortions unnecessary.
If the conclusion is that mixed arithmetic comparisons makes sense finally, and that we should better avoid having the unordered {1/2<0.5. 1/2=0.5. 1/2>0.5} -> #(false false false), that's already a point. The "painful contortions" is adressing another problem: that of transitivity as a principle of least astonishment. You say starting from a more consistent place, but how consistent are = and <= among Numbers without transitivity? If we can maintain the invariant with a pair of double dispatching methods and coordinated hash, why shouldn't we? Why lispers did it? (Scheme too) For me it's like saying: "since float are inexact, we have a license to waste ulp". We have not. IEEE 754 model insists on operations to be exactly rounded. These are painful contortions too, but most useful! Extending the contortion to exact comparison sounds a natural extension to me, the main difference is that we do not round true or false to the nearest float, so it's even nicer!
On 7/11/14 17:19 , Nicolas Cellier wrote:
2014-07-12 1:29 GMT+02:00 Andres Valloud <avalloud@smalltalk.comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net>>:
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before:
{1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false).
IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base.
IME, that's because loose code appears to work. What enables that loose code to work is the loose mixed mode arithmetic. I could understand integers and fractions. Adding floating point to the mix stops making as much sense to me.
Equality between floating point numbers does make sense. Equality between floating point numbers and scaled decimals or fractions... in general, I don't see how they could make sense. I'd rather see the scaled decimals and fractions explicitly converted to floating point numbers, following a well defined procedure, and then compared...
Andres.
Why do such mixed arithmetic comparisons make sense? Maybe we used floating points in some low level Graphics for optimization reasons. After these optimized operations we get a Float result by contagion, but our intention is still to handle Numbers. It would be possible to riddle the code with explicit asFloat/asFraction conversions, but that does not feel like a superior solution...
OK, we can as well convert to inexact first before comparing for this purpose. That's what C does, because C is too low level to ever care of transitivity and equivalence relationship. It's not even safe in C because the compiler can decide to promote to a larger precision behind your back... But let's ignore this "feature" and see what lispers recommend instead:
http://www.lispworks.com/documentation/lcl50/aug/aug-170.html
It says:
In general, when an operation involves both a rational and a floating-point argument, the rational number is first converted to floating-point format, and then the operation is performed. This conversion process is called /floating-point contagion/ <http://www.lispworks.com/reference/lcl50/aug/aug-193.html#MARKER-9-47>.
However, for numerical equality comparisons, the arguments are compared using rational arithmetic to ensure transitivity of the equality (or inequality) relation.
So my POV is not very new, it's an old thing. It's also a well defined procedure, and somehow better to my taste because it preserve more mathematical properties. If Smalltalk wants to be a better Lisp, maybe it should not constantly ignore Lisp wisdom ;)
We can of course argue about the utility of transitivity... As a general library we provide tools like Dictionary that rely on transitivity. You can't tell how those Dictionary will be used in real applications, so my rule of thumb is the principle of least astonishment. I've got bitten once by such transitivity while memoizing... I switched to a better strategy with double indirection as workaround: class -> value -> result, but it was surprising.
I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected).
That's allways what made me favour casual equality to universal inequality.
Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history...
Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
You say starting from a more consistent place, but how consistent are = and <= among Numbers without transitivity?
How are numbers consistent to begin with, when for all integers you have x + 1 ~= x but for floats, there are a multitude of values such that x + 1.0 = x holds? Addition is hardly the only operation that exhibits this kind of behavior. Or how about x = x being true for the vast majority of cases across all sorts of numbers, except when x is NaN? Integers and fractions don't even have a notion of -0.0. All of these are already pretty inconsistent without considering obvious issues such as 17 / 20 = 0.85 which in at least some Smalltalks evaluates to true even though it is mathematically impossible. The point is that classes like Float, Integer and Fraction may very well have a common superclass. Nonetheless, floating point numbers and effectively rationals obey very different rules. Both have their strong points, those strengths are maximized with consistency. Andres.
If we can maintain the invariant with a pair of double dispatching methods and coordinated hash, why shouldn't we? Why lispers did it? (Scheme too)
For me it's like saying: "since float are inexact, we have a license to waste ulp". We have not. IEEE 754 model insists on operations to be exactly rounded. These are painful contortions too, but most useful! Extending the contortion to exact comparison sounds a natural extension to me, the main difference is that we do not round true or false to the nearest float, so it's even nicer!
On 7/11/14 17:19 , Nicolas Cellier wrote:
2014-07-12 1:29 GMT+02:00 Andres Valloud <avalloud@smalltalk.__comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net> <mailto:avalloud@smalltalk.__comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net>>>:
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before:
{1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false).
IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base.
IME, that's because loose code appears to work. What enables that loose code to work is the loose mixed mode arithmetic. I could understand integers and fractions. Adding floating point to the mix stops making as much sense to me.
Equality between floating point numbers does make sense. Equality between floating point numbers and scaled decimals or fractions... in general, I don't see how they could make sense. I'd rather see the scaled decimals and fractions explicitly converted to floating point numbers, following a well defined procedure, and then compared...
Andres.
Why do such mixed arithmetic comparisons make sense? Maybe we used floating points in some low level Graphics for optimization reasons. After these optimized operations we get a Float result by contagion, but our intention is still to handle Numbers. It would be possible to riddle the code with explicit asFloat/asFraction conversions, but that does not feel like a superior solution...
OK, we can as well convert to inexact first before comparing for this purpose. That's what C does, because C is too low level to ever care of transitivity and equivalence relationship. It's not even safe in C because the compiler can decide to promote to a larger precision behind your back... But let's ignore this "feature" and see what lispers recommend instead:
http://www.lispworks.com/__documentation/lcl50/aug/aug-__170.html <http://www.lispworks.com/documentation/lcl50/aug/aug-170.html>
It says:
In general, when an operation involves both a rational and a floating-point argument, the rational number is first converted to floating-point format, and then the operation is performed. This conversion process is called /floating-point contagion/ <http://www.lispworks.com/__reference/lcl50/aug/aug-193.__html#MARKER-9-47 <http://www.lispworks.com/reference/lcl50/aug/aug-193.html#MARKER-9-47>>.
However, for numerical equality comparisons, the arguments are compared using rational arithmetic to ensure transitivity of the equality (or inequality) relation.
So my POV is not very new, it's an old thing. It's also a well defined procedure, and somehow better to my taste because it preserve more mathematical properties. If Smalltalk wants to be a better Lisp, maybe it should not constantly ignore Lisp wisdom ;)
We can of course argue about the utility of transitivity... As a general library we provide tools like Dictionary that rely on transitivity. You can't tell how those Dictionary will be used in real applications, so my rule of thumb is the principle of least astonishment. I've got bitten once by such transitivity while memoizing... I switched to a better strategy with double indirection as workaround: class -> value -> result, but it was surprising.
I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected).
That's allways what made me favour casual equality to universal inequality.
Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history...
Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
2014-07-12 11:55 GMT+02:00 Andres Valloud <avalloud@smalltalk.comcastbiz.net
:
You say starting from a more consistent place, but how consistent are =
and <= among Numbers without transitivity?
How are numbers consistent to begin with, when for all integers you have
x + 1 ~= x
but for floats, there are a multitude of values such that
x + 1.0 = x
holds? Addition is hardly the only operation that exhibits this kind of behavior. Or how about
x = x
being true for the vast majority of cases across all sorts of numbers, except when x is NaN? Integers and fractions don't even have a notion of -0.0. All of these are already pretty inconsistent without considering obvious issues such as
17 / 20 = 0.85
which in at least some Smalltalks evaluates to true even though it is mathematically impossible.
The point is that classes like Float, Integer and Fraction may very well have a common superclass. Nonetheless, floating point numbers and effectively rationals obey very different rules. Both have their strong points, those strengths are maximized with consistency.
Andres.
Yes, all is true, but it still is the same argument: - given Float are inexact we have a license to waste ulp - given Float OPERATIONS do not obey algebraic rules, we have a license to abandon mathematical properties at will I claim we'd better not be so liberal. Maybe I were a bit clumsy, but what I tried to say is that Float are not inexact per se. They carrry a well defined exact value. Only the operations are inexact. But they are the least inexact as possible: IEEE 754 requires that the operations behaves as if performed EXACTLY then result is rounded to nearest double (more exactly to the rounding rule currently in effect, nearest being the default rule). Comparisons can be exact, so I see no point in making them inexact. That's a bit against spirit of IEEE 754, even if they did not rule about mixed arithmetic. By making these comparisons exact, we preserve transitivity of = and <= which is not a bad thing. You know very well that VW has all the hacks to make hash preserve the equality of Float/Fraction/etc... What is the purpose of these hacks? Make Dictionary & al work? If so, why stopping in the middle of the bridge and let examples like http://bugs.squeak.org/view.php?id=3374 miserably fail? Being consistent then means either abandonning 1/2 = 0.5 but we saw this has nasty side effects. Or denying the generality of Dictionary: not all objects can be used as key... That's a possible choice, but IMO, this will generate bad feedback from customers. Speaking of consistency, I strongly believe that Squeak/Pharo are on the right track. OK, we can not magically erase inexactness of floating point operations. They are on purpose for the sake of speed/memory footprint optimization. Exceptional values like NaN and Inf are a great deal of complexification, and I'd allways preferred exceptions to exceptional values... But when we can preserve some invariants, we'd better preserve them. Once again, I did not invent anything, that's the approach of lispers, and it seems wise. And last thing, I like your argumentation, it's very logical, so if you have more, you're welcome but I pretty much exhausted mine ;) Nicolas
If we can maintain the invariant with a pair of double dispatching
methods and coordinated hash, why shouldn't we? Why lispers did it? (Scheme too)
For me it's like saying: "since float are inexact, we have a license to waste ulp". We have not. IEEE 754 model insists on operations to be exactly rounded. These are painful contortions too, but most useful! Extending the contortion to exact comparison sounds a natural extension to me, the main difference is that we do not round true or false to the nearest float, so it's even nicer!
On 7/11/14 17:19 , Nicolas Cellier wrote:
2014-07-12 1:29 GMT+02:00 Andres Valloud <avalloud@smalltalk.__comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net> <mailto:avalloud@smalltalk.__comcastbiz.net
<mailto:avalloud@smalltalk.comcastbiz.net>>>:
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before:
{1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false).
IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base.
IME, that's because loose code appears to work. What enables that loose code to work is the loose mixed mode arithmetic. I could understand integers and fractions. Adding floating point to the mix stops making as much sense to me.
Equality between floating point numbers does make sense. Equality between floating point numbers and scaled decimals or fractions... in general, I don't see how they could make sense. I'd rather see the scaled decimals and fractions explicitly converted to floating point numbers, following a well defined procedure, and then compared...
Andres.
Why do such mixed arithmetic comparisons make sense? Maybe we used floating points in some low level Graphics for optimization reasons. After these optimized operations we get a Float result by contagion, but our intention is still to handle Numbers. It would be possible to riddle the code with explicit asFloat/asFraction conversions, but that does not feel like a superior solution...
OK, we can as well convert to inexact first before comparing for this purpose. That's what C does, because C is too low level to ever care of transitivity and equivalence relationship. It's not even safe in C because the compiler can decide to promote to a larger precision behind your back... But let's ignore this "feature" and see what lispers recommend instead:
http://www.lispworks.com/__documentation/lcl50/aug/aug-__170.html <http://www.lispworks.com/documentation/lcl50/aug/aug-170.html>
It says:
In general, when an operation involves both a rational and a floating-point argument, the rational number is first converted to floating-point format, and then the operation is performed. This conversion process is called /floating-point contagion/ <http://www.lispworks.com/__reference/lcl50/aug/aug-193.__ html#MARKER-9-47
<http://www.lispworks.com/reference/lcl50/aug/aug-193. html#MARKER-9-47>>.
However, for numerical equality comparisons, the arguments are compared using rational arithmetic to ensure transitivity of the equality (or inequality) relation.
So my POV is not very new, it's an old thing. It's also a well defined procedure, and somehow better to my taste because it preserve more mathematical properties. If Smalltalk wants to be a better Lisp, maybe it should not constantly ignore Lisp wisdom ;)
We can of course argue about the utility of transitivity... As a general library we provide tools like Dictionary that rely on transitivity. You can't tell how those Dictionary will be used in real applications, so my rule of thumb is the principle of least astonishment. I've got bitten once by such transitivity while memoizing... I switched to a better strategy with double indirection as workaround: class -> value -> result, but it was surprising.
I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected).
That's allways what made me favour casual equality to universal inequality.
Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history...
Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
Being consistent then means either abandonning 1/2 = 0.5 but we saw this has nasty side effects.
Well ok, so letting 1 / 2 = 0.5 answer false has nasty side effects. Why is that? Isn't the code that breaks trying to tell us something? That's what I've been trying to point out. Why rush to defend numerically unstable code? What are we going to preserve, and what will be the example given to others? Andres.
Or denying the generality of Dictionary: not all objects can be used as key... That's a possible choice, but IMO, this will generate bad feedback from customers. Speaking of consistency, I strongly believe that Squeak/Pharo are on the right track.
OK, we can not magically erase inexactness of floating point operations. They are on purpose for the sake of speed/memory footprint optimization. Exceptional values like NaN and Inf are a great deal of complexification, and I'd allways preferred exceptions to exceptional values... But when we can preserve some invariants, we'd better preserve them. Once again, I did not invent anything, that's the approach of lispers, and it seems wise.
And last thing, I like your argumentation, it's very logical, so if you have more, you're welcome but I pretty much exhausted mine ;)
Nicolas
If we can maintain the invariant with a pair of double dispatching methods and coordinated hash, why shouldn't we? Why lispers did it? (Scheme too)
For me it's like saying: "since float are inexact, we have a license to waste ulp". We have not. IEEE 754 model insists on operations to be exactly rounded. These are painful contortions too, but most useful! Extending the contortion to exact comparison sounds a natural extension to me, the main difference is that we do not round true or false to the nearest float, so it's even nicer!
On 7/11/14 17:19 , Nicolas Cellier wrote:
2014-07-12 1:29 GMT+02:00 Andres Valloud <avalloud@smalltalk.__comcastb__iz.net <http://comcastbiz.net> <mailto:avalloud@smalltalk.__comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net>> <mailto:avalloud@smalltalk. <mailto:avalloud@smalltalk.>__c__omcastbiz.net <http://comcastbiz.net>
<mailto:avalloud@smalltalk.__comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net>>>>:
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before:
{1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false).
IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base.
IME, that's because loose code appears to work. What enables that loose code to work is the loose mixed mode arithmetic. I could understand integers and fractions. Adding floating point to the mix stops making as much sense to me.
Equality between floating point numbers does make sense. Equality between floating point numbers and scaled decimals or fractions... in general, I don't see how they could make sense. I'd rather see the scaled decimals and fractions explicitly converted to floating point numbers, following a well defined procedure, and then compared...
Andres.
Why do such mixed arithmetic comparisons make sense? Maybe we used floating points in some low level Graphics for optimization reasons. After these optimized operations we get a Float result by contagion, but our intention is still to handle Numbers. It would be possible to riddle the code with explicit asFloat/asFraction conversions, but that does not feel like a superior solution...
OK, we can as well convert to inexact first before comparing for this purpose. That's what C does, because C is too low level to ever care of transitivity and equivalence relationship. It's not even safe in C because the compiler can decide to promote to a larger precision behind your back... But let's ignore this "feature" and see what lispers recommend instead:
http://www.lispworks.com/____documentation/lcl50/aug/aug-____170.html <http://www.lispworks.com/__documentation/lcl50/aug/aug-__170.html> <http://www.lispworks.com/__documentation/lcl50/aug/aug-__170.html <http://www.lispworks.com/documentation/lcl50/aug/aug-170.html>>
It says:
In general, when an operation involves both a rational and a floating-point argument, the rational number is first converted to floating-point format, and then the operation is performed. This conversion process is called /floating-point contagion/
<http://www.lispworks.com/____reference/lcl50/aug/aug-193.____html#MARKER-9-4... <http://www.lispworks.com/__reference/lcl50/aug/aug-193.__html#MARKER-9-47>
<http://www.lispworks.com/__reference/lcl50/aug/aug-193.__html#MARKER-9-47 <http://www.lispworks.com/reference/lcl50/aug/aug-193.html#MARKER-9-47>>>.
However, for numerical equality comparisons, the arguments are compared using rational arithmetic to ensure transitivity of the equality (or inequality) relation.
So my POV is not very new, it's an old thing. It's also a well defined procedure, and somehow better to my taste because it preserve more mathematical properties. If Smalltalk wants to be a better Lisp, maybe it should not constantly ignore Lisp wisdom ;)
We can of course argue about the utility of transitivity... As a general library we provide tools like Dictionary that rely on transitivity. You can't tell how those Dictionary will be used in real applications, so my rule of thumb is the principle of least astonishment. I've got bitten once by such transitivity while memoizing... I switched to a better strategy with double indirection as workaround: class -> value -> result, but it was surprising.
I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected).
That's allways what made me favour casual equality to universal inequality.
Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history...
Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
2014-07-12 13:42 GMT+02:00 Andres Valloud <avalloud@smalltalk.comcastbiz.net
:
Being consistent then means either abandonning 1/2 = 0.5 but we saw this
has nasty side effects.
Well ok, so letting 1 / 2 = 0.5 answer false has nasty side effects. Why is that? Isn't the code that breaks trying to tell us something? That's what I've been trying to point out. Why rush to defend numerically unstable code? What are we going to preserve, and what will be the example given to others?
Andres.
What apparently breaks Pharo graphics is letting (1 comparisonOp: 1.0) = false in Float>>adaptToInteger:andCompare: (maybe my mistake, I should ^ operator = #~= rather than ^false) At this point, we can't tell that the code is numerically unstable. Maybe the Float are very well formed and sufficiently away from int, or exactly equal to int... Only if we see off-by-one errors can we conclude that there are design mistakes. Or if we perform a deeper analysis, but it ain't going to be easy. To know where it happens, we would have to instrument code (no static typing). It's not un-interesting. But it's going to waste a lot of time for a problem we don't yet have...
Or denying the generality of Dictionary: not all objects can be used as
key... That's a possible choice, but IMO, this will generate bad feedback from customers. Speaking of consistency, I strongly believe that Squeak/Pharo are on the right track.
OK, we can not magically erase inexactness of floating point operations. They are on purpose for the sake of speed/memory footprint optimization. Exceptional values like NaN and Inf are a great deal of complexification, and I'd allways preferred exceptions to exceptional values... But when we can preserve some invariants, we'd better preserve them. Once again, I did not invent anything, that's the approach of lispers, and it seems wise.
And last thing, I like your argumentation, it's very logical, so if you have more, you're welcome but I pretty much exhausted mine ;)
Nicolas
If we can maintain the invariant with a pair of double dispatching methods and coordinated hash, why shouldn't we? Why lispers did it? (Scheme too)
For me it's like saying: "since float are inexact, we have a license to waste ulp". We have not. IEEE 754 model insists on operations to be exactly rounded. These are painful contortions too, but most useful! Extending the contortion to exact comparison sounds a natural extension to me, the main difference is that we do not round true or false to the nearest float, so it's even nicer!
On 7/11/14 17:19 , Nicolas Cellier wrote:
2014-07-12 1:29 GMT+02:00 Andres Valloud <avalloud@smalltalk.__comcastb__iz.net <http://comcastbiz.net> <mailto:avalloud@smalltalk.__comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net>> <mailto:avalloud@smalltalk. <mailto:avalloud@smalltalk.>__c__omcastbiz.net <http://comcastbiz.net>
<mailto:avalloud@smalltalk.__comcastbiz.net <mailto:avalloud@smalltalk.comcastbiz.net>>>>:
I don't think it makes sense to compare floating point numbers to other types of numbers with #=... there's a world of approximations and other factors hiding behind #=, and the occasional true answer confuses more than it helps. On top of that, then you get x = y => x hash = y hash, and so the hash of floating point values "has" to be synchronized with integers, fractions, scaled decimals, etc... _what a mess_...
Yes, that's true, hash gets more complex. But then, this has been discussed before:
{1/2 < 0.5. 1/2 = 0.5. 1/2 > 0.5} - > #(false false false).
IOW, they are unordered. Are we ready to lose ordering of numbers? Practically, this would have big impacts on code base.
IME, that's because loose code appears to work. What enables that loose code to work is the loose mixed mode arithmetic. I could understand integers and fractions. Adding floating point to the mix stops making as much sense to me.
Equality between floating point numbers does make sense. Equality between floating point numbers and scaled decimals or fractions... in general, I don't see how they could make sense. I'd rather see the scaled decimals and fractions explicitly converted to floating point numbers, following a well defined procedure, and then compared...
Andres.
Why do such mixed arithmetic comparisons make sense? Maybe we used floating points in some low level Graphics for optimization reasons. After these optimized operations we get a Float result by contagion, but our intention is still to handle Numbers. It would be possible to riddle the code with explicit asFloat/asFraction conversions, but that does not feel like a superior solution...
OK, we can as well convert to inexact first before comparing for this purpose. That's what C does, because C is too low level to ever care of transitivity and equivalence relationship. It's not even safe in C because the compiler can decide to promote to a larger precision behind your back... But let's ignore this "feature" and see what lispers recommend instead:
http://www.lispworks.com/____documentation/lcl50/aug/aug-__ __170.html <http://www.lispworks.com/__documentation/lcl50/aug/aug-__ 170.html>
<http://www.lispworks.com/__documentation/lcl50/aug/aug-__ 170.html <http://www.lispworks.com/documentation/lcl50/aug/aug-170.html>>
It says:
In general, when an operation involves both a rational and a floating-point argument, the rational number is first converted to floating-point format, and then the operation is performed. This conversion process is called /floating-point contagion/
<http://www.lispworks.com/____reference/lcl50/aug/aug-193.__ __html#MARKER-9-47 <http://www.lispworks.com/__reference/lcl50/aug/aug-193.__ html#MARKER-9-47>
<http://www.lispworks.com/__reference/lcl50/aug/aug-193.__ html#MARKER-9-47 <http://www.lispworks.com/reference/lcl50/aug/aug-193. html#MARKER-9-47>>>.
However, for numerical equality comparisons, the arguments are compared using rational arithmetic to ensure transitivity of the equality (or inequality) relation.
So my POV is not very new, it's an old thing. It's also a well defined procedure, and somehow better to my taste because it preserve more mathematical properties. If Smalltalk wants to be a better Lisp, maybe it should not constantly ignore Lisp wisdom ;)
We can of course argue about the utility of transitivity... As a general library we provide tools like Dictionary that rely on transitivity. You can't tell how those Dictionary will be used in real applications, so my rule of thumb is the principle of least astonishment. I've got bitten once by such transitivity while memoizing... I switched to a better strategy with double indirection as workaround: class -> value -> result, but it was surprising.
I'm pretty sure a Squeak/Pharo image wouldn't survive that long to such a change (well I tried it, the Pharo3.0 image survives, but Graphics are badly broken as I expected).
That's allways what made me favour casual equality to universal inequality.
Also should 0.1 = 0.1 ? In case those two floats have been produced by different path, different approximations they might not be equal... (| a b | a := 0.1. b := 1.0e-20. a+b=a.) I also prefer casual equality there too. Those two mathematical expressions a+b and a are different but both floating point expressions share same floating point approximation, that's all what really counts because in the end, we cannot distinguish an exact from an inexact Float, nor two inexact Float. We lost the history...
Also, the inexact flag is not attached to a Float, it's only the result of an operation. Statistically, it would waste one bit for nothing, most floats are the result of an inexact operation. But who knows, both might be the result of exact operations too ;)
On 7/11/14 10:46 , stepharo wrote:
I suggest you to read the Small number chapter of the Deep into Pharo.
Stef
On 11/7/14 15:53, Natalia Tymchuk wrote:
Hello. I found interesting thing: Why it is like this?
Best regards, Natalia
2014-07-12 17:00 GMT+02:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
2014-07-12 13:42 GMT+02:00 Andres Valloud < avalloud@smalltalk.comcastbiz.net>:
Being consistent then means either abandonning 1/2 = 0.5 but we saw this
has nasty side effects.
Well ok, so letting 1 / 2 = 0.5 answer false has nasty side effects. Why is that? Isn't the code that breaks trying to tell us something? That's what I've been trying to point out. Why rush to defend numerically unstable code? What are we going to preserve, and what will be the example given to others?
Andres.
What apparently breaks Pharo graphics is letting (1 comparisonOp: 1.0) = false in Float>>adaptToInteger:andCompare: (maybe my mistake, I should ^ operator = #~= rather than ^false) At this point, we can't tell that the code is numerically unstable. Maybe the Float are very well formed and sufficiently away from int, or exactly equal to int... Only if we see off-by-one errors can we conclude that there are design mistakes. Or if we perform a deeper analysis, but it ain't going to be easy. To know where it happens, we would have to instrument code (no static typing).
It's not un-interesting. But it's going to waste a lot of time for a problem we don't yet have...
So I gave a try to instrumentation with one of my dirtiest hack: 1) define a new Notification subclass: #IntegerFloatComparison 2) raise this signal in Float>>adaptToInteger:andCompare: IntegerFloatComparison signal ...snip... 3) catch the senders using the message tally: tally := MessageTally new. tally spyEvery: 100 on: ['em ezilaitini ot si siht' reverse]. tally class: World class method: World class>>#doOneCycle. tallyEnd := false. [(Delay forSeconds: 300) wait. tallyEnd := true] fork. [[World doOneCycle. Processor yield.tallyEnd] whileFalse] on: IntegerFloatComparison do: [:exc | tally tally: exc signalerContext by: 1. exc resume]. (StringHolder new contents: (String streamContents: [:s | tally report: s])) openLabel: 'EndOfStream Spy Results'. 4) do your favourite activity... After 5 minutes of typical browsing/workspace activity, > 100 000 sends in Morph, TableLayout, bounds etc... But are the Float possibly ill-formed? I modified the signaller: (self fractionPart = 0) ifFalse: [IntegerFloatComparison signal]. Hmm 0 tallies this time. So I don't know where exactly Float are required (some primitive do not accept Fraction I think this is the main reason why some asFloat have been spreaded...). But these are innocuous Float. No numerical unstable code detected by this cheap exercize.
participants (13)
-
Andres Valloud -
Camille Teruel -
Esteban A. Maringolo -
Esteban Lorenzano -
Goubier Thierry -
Igor Stasenko -
kilon alios -
Luc Fabresse -
Natalia Tymchuk -
Nicolas Cellier -
Norbert Hartl -
stepharo -
Yuriy Tymchuk