## DOUBLE's fractional digits to ULONGINT ?

General FreeBASIC programming questions.
cbruce
Posts: 136
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

### DOUBLE's fractional digits to ULONGINT ?

Is there a math way to exactly translate a DOUBLE's fractional digits to a ULONGINT?

NOTE:
I do not want to convert a DOUBLE to a ULONGINT !!!
I want to translate a DOUBLE's fractional digits to a ULONGINT.
e.g. 0.876399937 ==> 876399937ull
I can get there with an intermediate STRING assignment - but that is a lot of overhead.

I can get there by multiplying a DOUBLE by a large ULONGINT CONST... but I would have to use a STRING version of the DOUBLE's fractional digits to get the length so that I could use the correct CONST for that set of digits. Because, without being able to choose the correct CONST for each set of digits, I sometimes end up with ULONGINT results that are too large - or sometimes with rounding errors. [see output examples below].

Code: Select all

`dim d as doubledim dsu as ulongintdim dmu as ulongint'print "Translate a DOUBLE's fractional digits to ULONGINT representation:"printprint "1. RND() DOUBLE"print "2. DOUBLE fractional digits to STRING to ULONGINT"print "3. DOUBLE Multiplied by CONST to ULONGINT"printFor i = 1 To 30    'RND() DOUBLE    d = RND()    'DOUBLE to STRING to ULONGINT - EXACT representation of the DOUBLE digits.    dsu = CULngInt(mid(str(d), 3))    'DOUBLE Multiplied by CONST to ULONGINT.    '   Sometimes an EXACT representation of the DOUBLE digits.    '   Sometimes a ROUNDED representation of the DOUBLE digits.    '   Sometimes 10 to 100 times greater than a representation of the DOUBLE digits.    'NOTE:    '   Attempted with various CONST values.    '   Some result is always off.    dmu = d * 10000000000000000ull    '    print tab(9); d    print tab(12); dsu    print tab(12); dmu    printnext`

Code: Select all

`' Output examples:'1. RND() DOUBLE'2. DOUBLE fractional digits to STRING to ULONGINT'3. DOUBLE Multiplied by CONST to ULONGINT' 0.5324827746953815'   5324827746953815'   5324827746953815     'same' 0.2956116099376231'   2956116099376231'   2956116099376232     'rounded up' 0.6646097381599248'   6646097381599248'   6646097381599247     'rounded down' 0.179675575112924'   179675575112924'   1796755751129240     'x10' 0.55096355965361'   55096355965361'   5509635596536100     'x100`
srvaldez
Posts: 2577
Joined: Sep 25, 2005 21:54

### Re: DOUBLE's fractional digits to ULONGINT ?

I understand your question but I don't see an easy solution, what's the reason for you wanting to do this?
perhaps there's a different approach to your problem.
cbruce
Posts: 136
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

### Re: DOUBLE's fractional digits to ULONGINT ?

I want to be able to generate a specified range of random doubles - not just the [0 to 1) range that a standard RND() that generates doubles does - but a range like [0.283834 to 0.9875922245]. And I haven't been able to figure out how to do that using only doubles.

The only way I could think of to do it is to translate the two doubles' digits to ulongints - generate a random value between the range of those ulongint values (which is easy to do) - and then convert the generated ulongint random value to a double (which is easy and fast to do).

With a RND() that generates ulongints, the example above would become RND(283834ull, 9875922245ull) - then you divide the ulongint result by &hffffffffffffffffull to create the resulting double.

Note: I want the RND() range parameters to actually be the doubles that the user wants to work with. I want to hide all of this manipulation inside the RND() function itself. The user just says RND(0.283834, 0.9875922245) and gets back their correct double result.
jj2007
Posts: 1818
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

### Re: DOUBLE's fractional digits to ULONGINT ?

The fpu has instructions that can isolate the fraction, but I can't get it to work in FB (Error: invalid use of register):

Code: Select all

`    d = RND()    asm fld d    asm fld st    asm frndint    asm fsubp    asm fistp dfu`
It works fine in another Basic dialect, but is this the output you want?

Code: Select all

`0.6017979375239967265   6017979375239967260.3345390753814613219   3345390753814613210.3800352918740010830   3800352918740010830.8916944829824631807   8916944829824631800.7454095696121832009   7454095696121832000.8613964000800220859   8613964000800220850.4389618751709885696   4389618751709885690.8379560746431650630   8379560746431650620.3001870129073617420   3001870129073617410.6476385100438799591   6476385100438799590.6796988126985414523   6796988126985414520.5406018366139318508   5406018366139318500.6898235518123229888   6898235518123229880.7596592812478851525   7596592812478851520.4607612095810701042   4607612095810701040.3866698474829880176   3866698474829880170.6984820022040093753   6984820022040093750.6082141741995020575   6082141741995020570.7680263217374531297   7680263217374531290.9728959023642265679   972895902364226567`

Source:

Code: Select all

`include \masm32\MasmBasic\MasmBasic.inc  SetGlobals dest:REAL10, dfu:QWORD, factor:QWORD=1000000000000000000  Init  FpuSet MbTrunc64  For_ ct=0 To 19   Rand(0.283834, 0.9875922245, dest)   Print Str\$("\n%Jf\t", dest)   fld dest   fld st   frndint   fsub   fild factor   fmul   fistp dfu   Print Str\$("%i", dfu)  Next EndOfCode`
Note that even with such a high precision (REAL10 is long double), and the high multiplication factor, there are always rounding errors. This is by design; if needed, you can tickle out one more digit if your upper random number lies below 0.92233720368547758.
paul doe
Posts: 1347
Joined: Jul 25, 2017 17:22
Location: Argentina

### Re: DOUBLE's fractional digits to ULONGINT ?

cbruce wrote:I want to be able to generate a specified range of random doubles - not just the [0 to 1) range that a standard RND() that generates doubles does - but a range like [0.283834 to 0.9875922245]. And I haven't been able to figure out how to do that using only doubles.

Could this be of any help?

Code: Select all

`function rndRange( byval min as double, byval max as double ) as double  return( rnd() * ( max - min ) + min )end functionrandomize()do while( inkey() = "" )   ? rndRange( 0.283834, 0.9875922245 )loop`
cbruce
Posts: 136
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

### Re: DOUBLE's fractional digits to ULONGINT ?

Perfect Paul! With that, I only need to convert my internal rng's ulongint result to a double and shove it into the equation. Simple and fast. A sliding range window... obvious once you see it. [smile]
Thanks!
paul doe
Posts: 1347
Joined: Jul 25, 2017 17:22
Location: Argentina

### Re: DOUBLE's fractional digits to ULONGINT ?

cbruce wrote:...A sliding range window... obvious once you see it. [smile]
Thanks!

You're welcome. The formula is simply a linear interpolation of the value returned by rnd(). Glad to help.
srvaldez
Posts: 2577
Joined: Sep 25, 2005 21:54

### Re: DOUBLE's fractional digits to ULONGINT ?

even though Rnd returns a double I am not sure of the precision of the number returned
FB Manual wrote:With the -lang fb dialect, a 32 bit Mersenne Twister function with a granularity of 32 bits is used.

srvaldez
Posts: 2577
Joined: Sep 25, 2005 21:54

### Re: DOUBLE's fractional digits to ULONGINT ?

jj2007 wrote:The fpu has instructions that can isolate the fraction, but I can't get it to work in FB (Error: invalid use of register):

Code: Select all

`    d = RND()    asm fld d    asm fld st    asm frndint    asm fsubp    asm fistp dfu`

Code: Select all

`dim shared dest as double, dfu as ulongint, factor as ulongint=1000000000000000000ullFor ct as long=0 To 19   dest=Rnd   Print dest,   asm      fld qword ptr [dest]      fld st(0)      frndint      fsubp st(1)      fild qword ptr [factor]      fmulp st(1)      fistp qword ptr [dfu]   end asm   Print dfuNext `
jj2007
Posts: 1818
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

### Re: DOUBLE's fractional digits to ULONGINT ?

Thanks, no more build errors. But the results do not convince me. Is ulongint = QWORD?
srvaldez
Posts: 2577
Joined: Sep 25, 2005 21:54

### Re: DOUBLE's fractional digits to ULONGINT ?

jj2007 wrote:But the results do not convince me. Is ulongint = QWORD?

of course, a longint is 64-bit
dodicat
Posts: 6761
Joined: Jan 10, 2006 20:30
Location: Scotland

### Re: DOUBLE's fractional digits to ULONGINT ?

If you map rnd to ten trillion (ten quintillion over the pond) then it looks like:

Code: Select all

`Function map(a As Double,b As Double,x As Double,c As Double,d As Double) As Ulongint    Return ((d)-(c))*((x)-(a))/((b)-(a))+(c)End Function#define U(x) culngint(x*10000000000000000000)For z As Long=1 To 50    Var x=Rnd    Print Tab(12); x    Print Tab(15);map(0,1,x,0,10000000000000000000)    Print Tab(15);U(x)    PrintNextSleep  `
jj2007
Posts: 1818
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

### Re: DOUBLE's fractional digits to ULONGINT ?

OK, it works:

Code: Select all

`dim shared dest as double, dfu as ulongint, factor as ulongint=1000000000000000000ullasm  push 3967  fclex  fldcw word ptr [esp]  pop edxend asm   For ct as long=0 To 19   dest=Rnd   Print dest,   asm      fld qword ptr [dest]      fld st(0)      frndint      fsubp st(1)      fild qword ptr [factor]      fmulp st(1)      fistp qword ptr [dfu]   end asm   Print dfuNextSleep`

Code: Select all

` 0.3300995409954339         330099540995433926 0.3290384791325778         329038479132577776 0.5324827746953815         532482774695381522 0.7599449595436454         759944959543645381 0.6424803049303591         642480304930359125 0.6527107947040349         652710794704034924 0.2956116099376231         295611609937623143 0.970114589901641          970114589901641011 0.9696021103300154         969602110330015420 0.9504357760306448         950435776030644774 0.5354314723517746         535431472351774573 0.6804801726248115         680480172624811530 0.07139793620444834        71397936204448342 0.6646097381599248         664609738159924745 0.0247647250071168         24764725007116794 0.4909006857778877         490900685777887701 0.03945830371230841        39458303712308406 0.4660093509592116         466009350959211587 0.8267167930025607         826716793002560734 0.8180722289253026         818072228925302624`
cbruce
Posts: 136
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

### Re: DOUBLE's fractional digits to ULONGINT ?

Although I don't need this anymore, you are missing one of the errors that I found in this attempt to multiply a double by a ulongint constant to get an exact representation of the doubles fractional digits as a ulongint value.

The constant must be the correct value in relation to the length of the number of digits in the double's fractional component - or else the resulting ulongint will either have too few or too many digits.

From your example of using a const of 1000000000000000000ull ... none of these are correct - (in fact most of them are wrong):

Code: Select all

`0.5324827746953815         5324827746953815220.9696021103300154         969602110330015420.6804801726248115         680480172624811530`

So you would have to count the digits in the fractional component in order to figure out which const value to multiply by.

That's why I had ended up working with strings - in order to get the exact representation of the digits of the fractional component.

Example:
If I was looking for a max range double of 0.6804801726248115 - and I ended up with a max range ulongint of 680480172624811530 to use in the random range calculation - I could easily end up with a random ulongint, that when translated back to a double, would be a larger value than the max double requested, etc.
integer
Posts: 392
Joined: Feb 01, 2007 16:54
Location: usa

### Re: DOUBLE's fractional digits to ULONGINT ?

cbruce wrote:I want to be able to generate a specified range of random doubles - not just the [0 to 1) range that a standard RND() that generates doubles does - but a range like [0.283834 to 0.9875922245]. And I haven't been able to figure out how to do that using only doubles.

The only way I could think of to do it is to translate the two doubles' digits to ulongints - generate a random value between the range of those ulongint values (which is easy to do) - and then convert the generated ulongint random value to a double (which is easy and fast to do).

With a RND() that generates ulongints, the example above would become RND(283834ull, 9875922245ull) - then you divide the ulongint result by &hffffffffffffffffull to create the resulting double.

Note: I want the RND() range parameters to actually be the doubles that the user wants to work with. I want to hide all of this manipulation inside the RND() function itself. The user just says RND(0.283834, 0.9875922245) and gets back their correct double result.

Code: Select all

`function GetRandomValueBetweenLimits(byval LowValue as double, byval HiValue as double ) as double    dim as double range = Hivalue - LowValue    return (LowValue + rnd * range )end function''driver    dim as double Lo, Hi, SomeWhereBetwixt    randomize    print " First#",," Between'em",," 2ndNumber"    for i as long = 1 to 10        Lo = rnd        Hi = rnd        SomeWhereBetwixt = GetRandomValueBetweenLimits(Lo, Hi)        print Lo, SomeWhereBetwixt, Hi    next i    getkey`

I believe dodicat posted the algo for this.