Jump to page: 1 24  
Page
Thread overview
Floating point rounding modes: we should restrict them slightly
Sep 10, 2009
Don
Sep 10, 2009
#ponce
Sep 10, 2009
Don
Sep 10, 2009
Jimbob
Sep 10, 2009
Lionello Lunesu
Sep 10, 2009
Rainer Deyke
Sep 10, 2009
Don
Sep 10, 2009
Michel Fortin
Sep 10, 2009
Don
Sep 11, 2009
Stewart Gordon
Sep 13, 2009
Don
Sep 13, 2009
Stewart Gordon
Sep 14, 2009
Don
Sep 14, 2009
Rainer Deyke
Sep 14, 2009
Don
Sep 15, 2009
Rainer Deyke
Sep 15, 2009
Don
Sep 15, 2009
Rainer Deyke
Sep 16, 2009
Don
Sep 16, 2009
Rainer Deyke
Sep 17, 2009
Don
Sep 14, 2009
Jason House
Sep 14, 2009
Denis Koroskin
Sep 11, 2009
Walter Bright
Sep 13, 2009
Don
Sep 13, 2009
Michel Fortin
Sep 13, 2009
Don
Sep 13, 2009
Walter Bright
Sep 13, 2009
Walter Bright
Sep 13, 2009
bearophile
Sep 14, 2009
Walter Bright
Sep 14, 2009
Don
Sep 14, 2009
Walter Bright
Sep 14, 2009
bearophile
Sep 14, 2009
Don
Sep 14, 2009
Brad Roberts
Sep 14, 2009
Walter Bright
Sep 15, 2009
Don
September 10, 2009
A quiz:
Conside a function
real foo() {....}
This is not pure, so that it may side-effects, but even so, are listings one and two equivalent?

LISTING ONE:

real x = foo(1) + foo(2) + foo(3);

LISTING TWO:

real x1 = foo(1);
real x2 = foo(2);
real x3 = foo(3);
real x = x1 + x2 + x3;

In C and C++ (and currently in D), they are NOT equivalent!
foo() is allowed to change the floating-point rounding mode, so it could change the meaning of '+'.
This is quite ridiculous. This is a 'freedom' that comes with a heavy price tag.
Actually doing this would make code nearly impossible to debug, and I don't think anyone is stupid enough to actually do this
...but as long as it's theoretically possible, it prevents the compiler from doing useful optimisations.
Disallowing this kind of obscure, dangerous nonsense is, I think, part of the core mission of D.

PROPOSAL:
Change the spec by adding the line to float.html:
"If the floating-point rounding mode is changed within a function, it must be restored before the function exits. If this rule is violated (for example, by the use of inline asm), the rounding mode used for subsequent calculations is undefined."

This slight tightening of semantics can have a significant benefit for all floating-point code.
September 10, 2009
Why not imposing a rounding mode (ex :  toward minus infinity) ? And then disallowing to change it in assembly.

I mean, you can still do :
  round(x) as floor(x + 0.5L)
  ceil(x) as floor(x + 1.0L)

Iit would cost some precision with large floating-point number, but not much since rounding such large numbers has few meaning.

It would clear up the rounding-mode mess a bit.
September 10, 2009
Don wrote:
> Change the spec by adding the line to float.html:
> "If the floating-point rounding mode is changed within a function, it
> must be restored before the function exits.

Even if that function is called 'fesetround'?


-- 
Rainer Deyke - rainerd@eldwood.com
September 10, 2009
Rainer Deyke wrote:
> Don wrote:
>> Change the spec by adding the line to float.html:
>> "If the floating-point rounding mode is changed within a function, it
>> must be restored before the function exits.
> 
> Even if that function is called 'fesetround'?

Obviously not. In fact, I'd hope to even disallow fesetround() since it's too easy to abuse, and instead have an RAII struct to restore the mode automatically. But that's just syntax sugar.
September 10, 2009
#ponce wrote:
> Why not imposing a rounding mode (ex :  toward minus infinity) ?
> And then disallowing to change it in assembly.

You can't impose a rounding mode in a system language: rounding mode is a crucial feature in a few rare but very important cases. The trick is to allow those cases without polluting everything else. This tiny proposal gets rid of most the damage.

However, my previous proposal for fixing the interaction of 'pure' with rounding modes and exception handling, would allow the rounding mode to be round-to-nearest almost everywhere, and changeable only in impure functions inside modules marked module(advancedfloatingpoint). This could give performance benefits everywhere outside those modules.

September 10, 2009
"#ponce" <aliloko@gmail.com> wrote in message news:h8adr2$23p3$1@digitalmars.com...
> Why not imposing a rounding mode (ex :  toward minus infinity) ? And then disallowing to change it in assembly.
>
> I mean, you can still do :
>  round(x) as floor(x + 0.5L)
>  ceil(x) as floor(x + 1.0L)
>
> Iit would cost some precision with large floating-point number, but not much since rounding such large numbers has few meaning.
>
> It would clear up the rounding-mode mess a bit.

There's more to rounding modes than just converting / rounding to integer. Rounding affects all arithmetic operations, and whether an expresion evaluates to 0.97999 or .97998 can be important in some cases.






September 10, 2009
On 2009-09-10 04:24:38 -0400, Don <nospam@nospam.com> said:

> PROPOSAL:
> Change the spec by adding the line to float.html:
> "If the floating-point rounding mode is changed within a function, it must be restored before the function exits. If this rule is violated (for example, by the use of inline asm), the rounding mode used for subsequent calculations is undefined."
> 
> This slight tightening of semantics can have a significant benefit for all floating-point code.

I perfectly agree. I'm just wondering how to enforce it in the language.

Later in the thread you say:

> ... have an RAII struct to restore the mode automatically. But that's just syntax sugar.

But how do you prevent someone from writing:

	auto s = new roundingMode(...);

The only way you can really make sure it's scoped to a specific function is to call it from another function:

	R performWithRoundingMode(R)(flag roundingMode, lazy R result)
	{
		flag oldRoundingMode = getRoundingMode();
		setRoundingMode(roundingMode);
		try
			return result;
		finally
			setRoundingMode(oldRoundingMode);
	}

	auto i = performWithRoundingMode(TOWARDS_ZERO, 12 * 12);

Here you can't escape the scoping requirements.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

September 10, 2009
Michel Fortin wrote:
> On 2009-09-10 04:24:38 -0400, Don <nospam@nospam.com> said:
> 
>> PROPOSAL:
>> Change the spec by adding the line to float.html:
>> "If the floating-point rounding mode is changed within a function, it must be restored before the function exits. If this rule is violated (for example, by the use of inline asm), the rounding mode used for subsequent calculations is undefined."
>>
>> This slight tightening of semantics can have a significant benefit for all floating-point code.
> 
> I perfectly agree. I'm just wondering how to enforce it in the language.

Yes, it's not so obvious how to enforce it. However, in reality it's a rarely-used, system level feature, so relying on convention probably isn't too terrible in the short term.

> 
> Later in the thread you say:
> 
>> ... have an RAII struct to restore the mode automatically. But that's just syntax sugar.
> 
> But how do you prevent someone from writing:
> 
>     auto s = new roundingMode(...);

scope _should_ take care of that. I'm not sure that it does. Still, we just need to make it easy to do the right thing, and difficult to do the wrong thing.

> The only way you can really make sure it's scoped to a specific function is to call it from another function:
> 
>     R performWithRoundingMode(R)(flag roundingMode, lazy R result)
>     {
>         flag oldRoundingMode = getRoundingMode();
>         setRoundingMode(roundingMode);
>         try
>             return result;
>         finally
>             setRoundingMode(oldRoundingMode);
>     }
> 
>     auto i = performWithRoundingMode(TOWARDS_ZERO, 12 * 12);
> 
> Here you can't escape the scoping requirements.

Hmmm. Not ideal, but could be worse.
But anyway, the important thing is to codify in the spec that the floating point state must not change randomly.
For discussing syntax, I think we really need an interval arithmetic module, so that we can ensure it all works well.
September 10, 2009
#ponce wrote:
> Why not imposing a rounding mode (ex :  toward minus infinity) ? And then disallowing to change it in assembly.
> 
> I mean, you can still do :
>   round(x) as floor(x + 0.5L)
>   ceil(x) as floor(x + 1.0L)
> 
> Iit would cost some precision with large floating-point number, but not much since rounding such large numbers has few meaning.
> 
> It would clear up the rounding-mode mess a bit.

Shouldn't ceil(1.0) return 1.0, and wouldn't floor(1.0 + 1.0L) return 2.0?

L.
September 11, 2009
Don wrote:
<snip>
> LISTING ONE:
> 
> real x = foo(1) + foo(2) + foo(3);
> 
> LISTING TWO:
> 
> real x1 = foo(1);
> real x2 = foo(2);
> real x3 = foo(3);
> real x = x1 + x2 + x3;
> 
> In C and C++ (and currently in D), they are NOT equivalent!
> foo() is allowed to change the floating-point rounding mode, so it could change the meaning of '+'.
<snip>

This is just one aspect of it.  You could also call a pure function, change the rounding mode, and then call the pure function again on the same arguments.  The value returned would change, thereby violating the purity.

There has been some talk about pure functions in relation to locales:

http://d.puremagic.com/issues/show_bug.cgi?id=3057
http://www.digitalmars.com/d/archives/digitalmars/D/std.locale_85081.html

Floating point settings are just another case of the same thing, except that currently violations in relation to the former are allowed.

Maybe the right solution is some kind of hidden parameter mechanism....

Stewart.
« First   ‹ Prev
1 2 3 4