## digitalmars.D - strange math

• Matt Watkins (50/50) Nov 23 2005 I am probably doing something dumb here, but I can't figure it out, so I...
Matt Watkins <Matt_member pathlink.com> writes:
```I am probably doing something dumb here, but I can't figure it out, so I am
wondering if someone here can help. I am trying to generate a random number
between 900 million and 1.1 billion, and store it in a float. Here are the two
code segments in question:

float div1;
//Code segment 1
for(int x = 0; x < 10; x++)
{
div1 = 1000000000.0f + cast(float)((rand() % 100000000) * ((rand() % 2) * 2 -
1));
writef("%f\n", div1);
}

//Code segment 2
for(int x = 0; x < 10; x++)
{
int addval = (rand() % 100000000) * ((rand() % 2) * 2 - 1);
div1 = 1000000000.0f + cast(float)(addval);
writef("%f\n", div1);
}

These two segments to me look like they should do the same thing. The only
difference between them is that the second segment uses a variable addval to do
(rand() % 100000000) * ((rand() % 2) * 2 - 1), where the first one just has the
code stuck right in the one line. Here is the output:
Code segment 1
1083211520.000000
5233628160.000000
5259153408.000000
1010581632.000000
5244919808.000000
1038838528.000000
1060295488.000000
5250748928.000000
5242580992.000000
1017323776.000000
Code segment 2
987565312.000000
901736640.000000
1040207936.000000
1039182272.000000
978791104.000000
1031670656.000000
1070735040.000000
997212864.000000
1054348672.000000
1069398592.000000
As you can see, the second segment behaves as expected, but the first segment
generates random numbers around 1 billion or around 5 billion. Can someone
please tell me why the first segment behaves the way it does? Thanks.

Also, I think I have the lastest version of the dmd compiler, since I updated no
more than 2 weeks ago.
```
Nov 23 2005
Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
```Hi,

In article <dm2ar6\$1h0f\$1 digitaldaemon.com>, Matt Watkins says...
I am probably doing something dumb here, but I can't figure it out, so I am
wondering if someone here can help. I am trying to generate a random number
between 900 million and 1.1 billion, and store it in a float. Here are the two
code segments in question:

float div1;
//Code segment 1
for(int x = 0; x < 10; x++)
{
div1 = 1000000000.0f + cast(float)((rand() % 100000000) * ((rand() % 2) * 2 -
1));
writef("%f\n", div1);
}

//Code segment 2
for(int x = 0; x < 10; x++)
{
int addval = (rand() % 100000000) * ((rand() % 2) * 2 - 1);
div1 = 1000000000.0f + cast(float)(addval);
writef("%f\n", div1);
}

These two segments to me look like they should do the same thing. The only
difference between them is that the second segment uses a variable addval to do
(rand() % 100000000) * ((rand() % 2) * 2 - 1), where the first one just has the
code stuck right in the one line. Here is the output:

[snip]

As you can see, the second segment behaves as expected, but the first segment
generates random numbers around 1 billion or around 5 billion. Can someone
please tell me why the first segment behaves the way it does? Thanks.

Welcome to the wonderful world of integral promotion. :)
I've been bitten by exactly this before... (see
http://www.digitalmars.com/d/archives/digitalmars/D/28116.html)

Here is a breakdown of why this happens: (I hope it is possible to follow)

rand() returns uint
uint % int gets promoted to uint
uint * int gets promoted to uint
uint - int gets promoted to uint
((rand() % 2) * 2 - 1) therefore gets promoted to uint...

This give two possible numbers:
1u or 4294967295u

(rand() % 100000000) also gets promoted to uint
two uints get multiplied giving a new uint (will overflow in 50% of the cases)

Assume (rand() % 100000000) evaluates to 99999999u...

the wounderful nature of 2-compliment math gives:

cast(int) 4294967295u * 99999999u == -99999999

Therefore, everything works in the second case.

in the first case, you have instead:

cast(float) 4294967295u * 99999999u == 4.19497e+09 (approximately)

And everything blows up.

The cleanest fix to your code may be:

#float div1;
#//Code segment 1
#for(int x = 0; x < 10; x++)
#{
#  div1 = 1000000000.0f + cast(float)((rand() % 100000000) * cast(int)((rand() %
2) * 2 - 1));
#  writef("%f\n", div1);
#}

Note: You will get exactly the same results in C. (Not that I've tested...)

D has the same integral promotion rules as C has.

Regards

Oskar
```
Nov 23 2005