r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[!REBOL3-OLD1]

Geomol
2-Jul-2009
[15907]
I'm in doubt about the distribution of numbers. Is this R2 function 
calculating ulps between two number ok?

ulps: func [
    value1 
    value2 
    /local d1 d2
][
    d: make struct! [v [decimal!]] none 
    d1: make struct! [hi [integer!] lo [integer!]] none 
    d2: make struct! [hi [integer!] lo [integer!]] none 
    d/v: value1 
    change third d1 third d 
    d/v: value2 
    change third d2 third d 
    print [d1/hi d1/lo d2/hi d2/lo] 
    print [d1/hi - d2/hi * (2 ** 32) + d1/lo - d2/lo]
]
Ladislav
2-Jul-2009
[15908]
suggestion: R3
Geomol
2-Jul-2009
[15909]
The reason, I prefer your first version is:
- I always know the endpoints exactly.
- The mean is well defined.
- The function is simpler and faster.
Ladislav
2-Jul-2009
[15910x2]
REBOL [
    Author: "Ladislav Mecir"
    Purpose: {Converts decimal to ordinal and back}
]

make object! [
    int-min: to integer! #{8000000000000000}
    set 'dec-as-int func [x [decimal!]] [
        x: to integer! to binary! x
        either x < 0 [int-min - x] [x]
    ]
    set 'int-as-dec func [x [integer!]] [
        if x < 0 [x: int-min - x]
        to decimal! to binary! x
    ]
]
your "difference in ulps" is just the difference between the ordinal 
numbers
Geomol
2-Jul-2009
[15912x2]
So an R3 ulps could be:

ulps: func [
	lo	[decimal!]
	hi	[decimal!]
][
	(to-integer to-binary hi) - to-integer to-binary lo
]
>> ulps 0.0 0.1
== 4591870180066957722
>> ulps 0.1 0.2
== 4503599627370496
Ladislav
2-Jul-2009
[15914]
(as-int hi) - (as-int lo)
Geomol
2-Jul-2009
[15915]
It seems, numbers lie much closer around zero than around 0.1.
Ladislav
2-Jul-2009
[15916]
sorry, (dec-as-int hi) - (dec-as-int lo)
Geomol
2-Jul-2009
[15917x2]
>> (dec-as-int 0.1) - (dec-as-int 0.0)
== 4591870180066957722
>> (dec-as-int 0.2) - (dec-as-int 0.1)
== 4503599627370496

Same result. Now I'm confused! :-)
If this is correct, then my suggestion to do
random 1.0
many times will actually show the problem.
Ladislav
2-Jul-2009
[15919x2]
yes, you get different result only when trying (dec-as-int 0.0) - 
(dec-as-int -0.0)
etc.
Geomol
2-Jul-2009
[15921x5]
The highest decimal is
>> to-decimal #{7fef ffff ffff ffff}
== 1.79769313486232e+308


There is the same number of ulps between 0.0 and 2.0 as between 1.0 
and the highest decimal:

>> ulps 0.0 2.0
== 4611686018427387904
>> ulps 1.0 to-decimal #{7fef ffff ffff ffff}
== 4611686018427387903


I think, the space between number are different all the way from 
zero to the highest decimal, but I'm not sure.
space between *numbers* are ...
Funnily enough, 1.5 is the middle value when talking ulps:

>> ulps 0.0 1.5
== 4609434218613702656
>> ulps 1.5 hi
== 4609434218613702655
where hi is:
hi: to-decimal #{7fef ffff ffff ffff}
This mean, there is as many different possible decimals between 0.0 
and 1.5 as between 1.5 and the highest possible 64-bit decimal, when 
talking floating points in a computer using the 64-bit IEEE 754 standard.
Ladislav
2-Jul-2009
[15926x2]
how about this, do you think, that there is a problem with it too?
two**62: to integer! 2 ** 62
two**9: to integer! 2 ** 9
two**53: to integer! 2 ** 53
r-uni: func [x [decimal!] /local d] [
	d: random two**62
	; transform to 0..2**53-1
	d: d // two**53
	; transform to 0.0 .. x (0.0 inclusive, x exclusive)
	d / two**53 * x
]
a modification:

two**62: to integer! 2 ** 62
two**53: to integer! 2 ** 53
two**53+1: two**53 + 1
r-uni: func [x [decimal!] /local d] [
	d: random two**62
	; transform to 0..2**53
	d: d // two**53+1
	; transform to 0.0 .. x (0.0 inclusive, x inclusive)
	d / two**53 * x
]
BrianH
2-Jul-2009
[15928]
When you two are done, could you look at CureCode ticket #1027 and 
R3's alpha 66 behavior and see if it is correct? I can't judge.
Ladislav
2-Jul-2009
[15929x2]
LOL, that is what we are just discussing
anyway, this is always a problem, when we try to generate numbers 
in an "exotic" interval, not in the usual [0.0 .. 1.0]
Geomol
2-Jul-2009
[15931]
I'll just grab some food, then I look at your r-uni.
Ladislav
2-Jul-2009
[15932]
hmm, seems, that the former may still produce X when rounding?
Gregg
2-Jul-2009
[15933]
In any case, this chat should be the basis for the docs that go with 
it. People aren't aware of how much thought goes into these things.
Geomol
2-Jul-2009
[15934x2]
>> two**62 / two**53+1
== 512.0

So two**53+1 * 512 should equal two**62, but it doesn't:

>> two**62
== 4611686018427387904
>> two**53+1 * 512
== 4611686018427388416

Why is that?
(I wanted to check , if d // two**53+1 gave an even distribution, 
but there seem to be something wrong with calculations of large numbers.)
Ladislav
2-Jul-2009
[15936]
Why is that?
 - rounding
Geomol
2-Jul-2009
[15937]
This should give an math overflow, I think:

>> to integer! 2 ** 62
== 4611686018427387904

Like this does in R2:

>> to integer! 2 ** 31
** Math Error: Math or number overflow
Ladislav
2-Jul-2009
[15938]
no, R3 uses 64-bit integers
Geomol
2-Jul-2009
[15939x3]
no wait, it's 2 ** 63, that should give overflow.
yeah
But!? :-)

>> to integer! 2 ** 62 - 1
== 4611686018427387904
>> to integer! 2 ** 62
== 4611686018427387904

Isn't that a bug?
Ladislav
2-Jul-2009
[15942]
no, it is the precision limit of IEEE754
Geomol
2-Jul-2009
[15943]
I see.
Ladislav
2-Jul-2009
[15944]
(I mean, it exceeds the precision limit)
Geomol
2-Jul-2009
[15945x2]
Yes, I understand.
After you do:

d: d // two**53+1


Are we sure, the new d is even distributed? That every value, d can 
now take, is equal possible?
Ladislav
2-Jul-2009
[15947x2]
hmm, to make sure, I should use rejection
as follows:

rnd: func [
	{random range with rejection, not using last bits}
	value [integer!]
	/local r s
] [
	s: two-to-62 - (two-to-62 // value)
	until [
		r: random two-to-62
		r <= s
	]
	s: s / value
	r - (r // s) / s + 1
]
Geomol
2-Jul-2009
[15949]
If all possible values of d is equal possible, and d now can have 
values from 0 to two**53, then

d / two**53

will return values from 0.0 to 1.0 both inclusive, and 

d / two**53 * x

will return values from 0.0 to x both inclusive. Right?
Ladislav
2-Jul-2009
[15950x2]
yes
...multiplication may still trigger rounding, though
Geomol
2-Jul-2009
[15952]
It give same result as your first RANDOM:

d: to-decimal to-binary 1023
blk: []
insert/dup blk 0 1024
random/seed now

loop 1000000 [i: to-integer to-binary r-uni d blk/(i + 1): blk/(i 
+ 1) + 1]

>> print [blk/1 blk/512 blk/1024]
462 1036 481
Ladislav
2-Jul-2009
[15953]
that is caused by the multiplication rounding
Geomol
2-Jul-2009
[15954x2]
yes
I like it better than the version, where max is changed to 0.0
Ladislav
2-Jul-2009
[15956]
another variant would be to generate the uniform deviates in the 
definite interval not allowing multiplication to "mess things"