September 11, 2009
Don wrote:
> 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."

But that doesn't allow for changing the rounding mode at a global level, then rerunning one's computation to determine how rounding affects their final result.
September 13, 2009
Walter Bright wrote:
> Don wrote:
>> 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."
> 
> But that doesn't allow for changing the rounding mode at a global level, then rerunning one's computation to determine how rounding affects their final result.

It doesn't prevent that at all. You just need to change the rounding mode before running your computation (at the start of main(), for example), and then reset it after performing the computation. What it does do is prevent different terms within a single expression from interacting which other.

eg
double foo() {
  return x() + y();
}
x() and y() can use whichever rounding modes they like, and if they are impure, they can affect one another, but under this proposal, they cannot change the meaning of the addition inside foo().
September 13, 2009
Stewart Gordon wrote:
> 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.

I already presented a proposal for that. This proposal is primarily for functions which are not pure.

> 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.

There's a fundamental difference between them: the floating point settings are a hardware feature and it is IMPOSSIBLE to avoid them. You can choose not to use locale settings. Or, you can pass them as a parameter, which doesn't work for floating point settings.

Please do not get sidetracked on pure functions, it is orthogonal to this issue.
September 13, 2009
On 2009-09-13 06:14:02 -0400, Don <nospam@nospam.com> said:

> double foo() {
>    return x() + y();
> }
> x() and y() can use whichever rounding modes they like, and if they are impure, they can affect one another, but under this proposal, they cannot change the meaning of the addition inside foo().

Problems still may occur if x and y do memoization however. You call x() with one rounding mode, it memoize the results, then call x() with another rounding mode and it reuses the previous results while it shouldn't.

Basicaly, any memoization of x() should be discarded when you change the rounding mode. For instance the compiler should not reuse the value of x(), even if x is pure, in the following code:

	auto a = x();
	setRoundingMode(...);
	auto b = x();

Basically, setRoundingMode should act as some sort of barrier for the optimizer, but how?

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

September 13, 2009
Michel Fortin wrote:
> On 2009-09-13 06:14:02 -0400, Don <nospam@nospam.com> said:
> 
>> double foo() {
>>    return x() + y();
>> }
>> x() and y() can use whichever rounding modes they like, and if they are impure, they can affect one another, but under this proposal, they cannot change the meaning of the addition inside foo().
> 
> Problems still may occur if x and y do memoization however. 

Yes, but this is an orthogonal issue, which I have discussed previously.

> Basicaly, any memoization of x() should be discarded when you change the rounding mode.

> Basically, setRoundingMode should act as some sort of barrier for the optimizer, but how?

It's not a big deal, because rounding mode is changed so rarely, so you don't need to exactly catch all the cases where memoisation can safely be used; you only need to disallow all of the ones where it is unsafe.

I proposed two options: (1) by analogy to SafeD, allow rounding mode and float exception flags to be respected only in specially marked modules ('module(advancedfloatingpoint)' or similar). Memoisation should be disabled in such modules. (As a further optimisation, the compiler can re-enable memoisation when such functions are called from non-advancedfloatingpoint modules).
(2) provide a runtime call to disable memoisation. You'd be obliged to call this every time you changed the rounding mode or exception status from the default.

I favour (1) because it provides huge optimisation potential for modules with default floating point.

The point of all my proposals on this topic, is that these features cause a lot of trouble if they're completely unrestrained in the way that C/C++ does it, but the semantics required to completely domesticate them are not burdensome, and can be done without loss of useful functionality.
September 13, 2009
Walter Bright wrote:
> Don wrote:
>> 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."
> 
> But that doesn't allow for changing the rounding mode at a global level, then rerunning one's computation to determine how rounding affects their final result.

Ok, I understand now. This makes sense.
September 13, 2009
Don wrote:
> 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."


I added it into float.html for D2.
September 13, 2009
Don wrote:
<snip>
>> Floating point settings are just another case of the same thing, except that currently violations in relation to the former are allowed.
> 
> There's a fundamental difference between them: the floating point settings are a hardware feature and it is IMPOSSIBLE to avoid them.

Actually, you _can_ avoid changing the floating point settings in the course of an average program.  But still....

> You can choose not to use locale settings. Or, you can pass them as a parameter, which doesn't work for floating point settings.

As long as it's the built-in arithmetic operators you're concerned about.  But that said, wrapping every arithmetic operation in a function to purify it of dependence on floating point settings wouldn't be ideal.

> Please do not get sidetracked on pure functions, it is orthogonal to this issue.

I'm not sure about this.  ISTM arithmetic operators are essentially pure functions, and so the compiler may treat them as such.

Stewart.
September 13, 2009
Walter Bright:

> Don:
> > 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."
> 
> I added it into float.html for D2.

An important purpose of a not bug-prone language is remove as many undefined situations as possible. If you add that to D2 specs, can the compiler catch at compile time all cases of violations to that rule?

D has something for the actions that must be done before the function exits, the scope(exit). Can something like that be used to automatically avoid undefined rounding situations?

Bye,
bearophile
September 14, 2009
bearophile wrote:
> An important purpose of a not bug-prone language is remove as many
> undefined situations as possible.

That's right.

> If you add that to D2 specs, can
> the compiler catch at compile time all cases of violations to that
> rule?

Unlikely. But that has to be weighed against the former behavior being defined in a useless way.


> D has something for the actions that must be done before the function
> exits, the scope(exit). Can something like that be used to
> automatically avoid undefined rounding situations?

Using an RAII object to do it might be better.