August 20, 2022
On Saturday, 20 August 2022 at 12:53:28 UTC, Adam D Ruppe wrote:
> ---
> void main() {
>         float f = 7.0;
>         f /= 0;
>         import core.stdc.stdio;
>         printf("%d\n", *cast(int*)&f);
>         if(f is float.init)
>                 printf("nan\n");
> }
> ---
>
> That's a different nan than the float.init pattern. I don't know if you can start with a float.init and come up with a different pattern though, but i expect you can.

Thanks. The above is infinity though.

	f = 1.0;
	f /= 0;
	assert(f is f.infinity);

This produces a different NaN:

	float f = 0;
	f /= 0;
	assert(f is f.nan); //fails

August 20, 2022
On Saturday, 20 August 2022 at 05:18:20 UTC, Walter Bright wrote:
> On 8/19/2022 8:12 PM, Steven Schveighoffer wrote:
>> [...]
>
> I don't see how. Any operation with a NaN produces a NaN result. If you've got a NaN result, it can be traced back to its source. This is hard with 0 initialization.
>
>
>> [...]
>
> I don't know why floating point for drawing coordinates? Besides, when I wonder if a function is being called, I put a printf in it. Or set a breakpoint in the debugger. This is routine debugging work. Then I'll look at the values of the parameters. Again, routine. Back in the olden days, I'd have the embedded system click the speaker to see if it entered a function :-)
>
>
>> [...]
>
> It is not silent. Every single usage of NaN produces a NaN result. If printing a NaN value, the result is "NaN".
>
>
>> [...]
>
> struct S { float x = 0; }
>
>
>> [...]
>
> Because I've seen what happens with that. The compiler complains about no initializer, and the programmer just puts in "0" to shut up the compiler. He does not make the effort to figure out what it should be initialized to. The reviewer wastes time trying to figure why it is uselessly initialized to zero.
>
> This is an especial problem when the initialized value is never used. The reviewer is left wondering if it is a bug. D is designed this way so that explicit initializations to a value are *intentional* rather than a side effect of compiler error messages.
>
> This is all part of D's design to encourage writing code that is easier to debug, review and maintain. Even if it takes a little more writing up front.


Drawing with float is required a lot on modern drawing API. What motivated me doing that post was firstly because I was sending OpenGL NaN coordinates, which resulted in needing a gpu debugger for that.

I don't see how easier it is to track a nan. Division by zero causes exception which is the best thing ever. Multiplication produces a zero result, which is pretty obvious to track. If the number does not change you will pretty much print both values and you'll easily find the 0 there.
August 20, 2022
On Saturday, 20 August 2022 at 13:06:49 UTC, Nick Treleaven wrote:
> Thanks. The above is infinity though.

oh yeah i forgot about that rule

> This produces a different NaN:

yes, thanks!

August 20, 2022

On Friday, 19 August 2022 at 17:14:35 UTC, Steven Schveighoffer wrote:

>
ReallyLargeStruct foo = { 0 };

There just is no equivalent in D. In order to set all fields to 0, I would have to specify a complete layout of the entire thing. This could probably be done via introspection. But I just don't like it even in that case.

Maybe something like this:

template ZeroInit(T)
{
	union U
	{
		byte[T.sizeof] a;
		T zeroed;
	}
	enum ZeroInit = U().zeroed;
}

struct S
{
	float f;
	float[2] a;
}

void main()
{
	S s = ZeroInit!S;
	assert(s.f == 0);
	assert(s.a == [0,0]);
}
August 20, 2022
On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:
> If there was a NaN value for int, I would have used it as the default. int.min is not really a NaN.

But it should be!
int.min is a notorious bogus value. You can't even use abs() on it: it will either give you a different type or return garbage. There is not even a working literal for it (at least for long.min). So it should never have been a valid value from beginning.
The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.
August 20, 2022
On Saturday, 20 August 2022 at 18:05:59 UTC, Dom Disc wrote:
> On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:
>> If there was a NaN value for int, I would have used it as the default. int.min is not really a NaN.
>
> But it should be!
> int.min is a notorious bogus value. You can't even use abs() on it: it will either give you a different type or return garbage. There is not even a working literal for it (at least for long.min). So it should never have been a valid value from beginning.
> The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.

By the way, you don't have to write this yourself; you can use Checked!(int, WithNaN) [1] from std.checkedint.

[1] https://phobos.dpldocs.info/std.checkedint.WithNaN.html
August 20, 2022
On Saturday, 20 August 2022 at 13:06:49 UTC, Nick Treleaven wrote:
>
> Thanks. The above is infinity though.
>
> 	f = 1.0;
> 	f /= 0;
> 	assert(f is f.infinity);
>
> This produces a different NaN:
>
> 	float f = 0;
> 	f /= 0;
> 	assert(f is f.nan); //fails

I never understood why the IEEE standard decided to include infinity. What were they trying to achieve? Indeterminate maths with floating point?
August 20, 2022
On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:
> The NaN value for char is 0xFF [...]. [...] (0xFF is specified as an illegal
> code point in Unicode.)

The code point OxFF = U+00FF is ÿ: <https://codepoints.net/U+00FF>. It is the code unit [1]: "In valid UTF-8, the bytes 0xF5..0xFF cannot occur."

[1] https://stackoverflow.com/questions/1319022/really-good-bad-utf-8-example-test-data
August 20, 2022

On Saturday, 20 August 2022 at 04:04:08 UTC, Ali Çehreli wrote:

>

I think the following is a solution to nan being inappropriate e.g. for Distance:

struct initted(T, T initValue) {
T value = initValue;
alias value this;
}

alias Distance = initted!(double, 0);

void main() {
Distance d; // Not a nan ;)
d += 1.5;
d /= 2;
assert(d == 0.75);
}

However, it is not type-safe enough because one can mix and match Distance with e.g. Temperature, which may not be correct for the program.

Ali

Enter std.typecons.Typefef:

import std;

alias Distance = Typedef!(double, 0.0, "distance");
alias Temperature = Typedef!(double, 0.0, "temperature");

void main()
{
    Temperature t;
    Distance d;
    d += 4.5;
    // t = d; // does not compile
}

However, type information can get lost in intermediate results:

    t = 0.5 + d; // result is double

— Bastiaan

August 20, 2022
On Saturday, 20 August 2022 at 18:59:40 UTC, IGotD- wrote:
> I never understood why the IEEE standard decided to include infinity. What were they trying to achieve? Indeterminate maths with floating point?

I was curious about this too, so I did some searching. The Wikipedia page on floating-point arithmetic has a section titled "IEEE 754 design rationale" [1], which cites as one of its sources "Why do we need a floating-point arithmetic standard?" [2], a 1981 paper by William Kahan, one of the designers of IEEE 754.

In that paper (on page 31), Kahan gives the following rationale for including values like NaN and infinities:

> the proposed standard specifies rules for creating and manipulating sym-
> bols like ±0, ±∞ and NaN – the symbol “NaN ” stands for “Not a Number”.
> These rules are designed so that a programmer may frequently omit tests and
> branches that were previously obligatory because computers treated exceptions
> in unpredictable or capricious ways.
> [...]
> At the
> same time as NaN is created a flag called Invalid Operation is raised. Subse-
> quently the calling program may infer either from this flag or from the NaN that
> an emergency arose and may cope with it automatically rather than abort

So the point is to simplify error handling, and to allow error handling to be deferred.

[1] https://en.wikipedia.org/wiki/Floating-point_arithmetic#IEEE_754_design_rationale
[2] https://people.eecs.berkeley.edu/~wkahan/ieee754status/why-ieee.pdf