DOUBLE's fractional digits to ULONGINT ?

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

Re: DOUBLE's fractional digits to ULONGINT ?

Post by cbruce »

Yep, Integer... thanks... but paul doe already straightened me out on that a few posts above.

I was just pointing out the error in the direction of the on-going conversation.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: DOUBLE's fractional digits to ULONGINT ?

Post by jj2007 »

cbruce wrote: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.
Apparently you didn't read my post of Apr 09, 2018 2:16 above: There is no "correct" value. What you get when converting a double to a string is always "incorrect". A double allows roughly 16 correct digits, a REAL10 about 19 (you can go beyond that with a bignum library, of course).
cbruce
Posts: 166
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Re: DOUBLE's fractional digits to ULONGINT ?

Post by cbruce »

Apologies jj2007... my comment about "errors" was not in relation to the purity of mathematics - but in relation to the purpose I was going to put the results to. As my example from a couple of posts ago explained:
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.
The *error* in question would cause magnitudes of difference when using a set of a DOUBLE's fractional digits in a ULONGINT representation. That was why the original purpose was to find a way (other than with strings) to get an *exact* representation of those digits - so that the magnitude would scale, correctly, along with the representation.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: DOUBLE's fractional digits to ULONGINT ?

Post by dodicat »

Here are two random rangers for ulongint and above.

Code: Select all

 
Function plus(Byval num1 As String,Byval num2 As String) As String
    Static As Const Ubyte AddQMod(0 To 19)={48,49,50,51,52,53,54,55,56,57,48,49,50,51,52,53,54,55,56,57}
    Static As Const Ubyte AddBool(0 To 19)={0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1}
    Var n_=0
    Dim As Ubyte addup=Any,addcarry
    #macro finish()
    Return Ltrim(answer,"0")
    #endmacro
    If Len(num2)>Len(num1) Then  Swap num2,num1
    Var diff=Len(num1)-Len(num2)
    Var answer="0"+num1
    For n_=Len(num1)-1 To diff Step -1 
        addup=num2[n_-diff]+num1[n_]-96
        answer[n_+1]=ADDQmod(addup+addcarry)
        addcarry=ADDbool(addup+addcarry)
    Next n_ 
    If addcarry=0 Then 
        finish()
    End If
    If n_=-1 Then 
        answer[0]=addcarry+48
        finish()
    End If
    For n_=n_ To 0 Step -1 
        addup=num1[n_]-48
        answer[n_+1]=ADDQmod(addup+addcarry)
        addcarry=ADDbool(addup+addcarry)
        If addcarry=0 Then Exit For
    Next n_
    answer[0]=addcarry+48
    finish()
End Function


Function minus(byval num1 As String,byval num2 As String) As String
    Static As Const Ubyte subqmod(19)={48,49,50,51,52,53,54,55,56,57,48,49,50,51,52,53,54,55,56,57}
    Static As Const Ubyte subbool(19)={1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0}
    Dim As Integer bigger          
    Dim sign As String * 1
    Var lenf=Len(NUM1)
    Var lens=Len(NUM2)
    #macro finishup()
    answer=Ltrim(answer,"0")
    If answer="" Then Return "0"
    Return sign+answer
    #endmacro
    #macro compare()
    If Lens>lenf Then bigger= -1:Goto fin
    If Lens<lenf Then bigger =0:Goto fin
    If NUM2>NUM1 Then 
        bigger=-1
    Else
        bigger= 0
    End If
    fin:
    #endmacro
    
    compare()
    If bigger Then 
        sign="-"
        Swap NUM2,NUM1
        Swap lens,lenf
    End If
    Var diff=lenf-lens
    Dim As String answer=NUM1
    Dim As Integer n
    Dim As Ubyte takeaway,subtractcarry
    subtractcarry=0
    For n=lenf-1 To diff Step -1 
        takeaway= num1[n]-num2[n-diff]+10-subtractcarry
        answer[n]=Subqmod(takeaway)
        subtractcarry=Subbool(takeaway)
    Next n 
    
    If subtractcarry=0 Then:finishup():End If
    If n=-1 Then:finishup():End If
    For n=n To 0 Step -1 
        takeaway= num1[n]-38-subtractcarry 
        answer[n]=Subqmod(takeaway)
        subtractcarry=Subbool(takeaway)
        If subtractcarry=0 Then Exit For
    Next n
    finishup()
End Function  

Function Get64Bit() As UlongInt
  Return (Cast( Ulongint, Rnd*(2^32) ) Shl 32) Or Cast( Ulongint, Rnd*(2^32) )   
End Function   

Function rndX overload(s1 As String) As String
    #macro GetNumber
    #define range(f,l) Int(Rnd*((l+1)-(f))+(f))
    s[0]=range(48,s1[0])
    For n As Long = 1 To L-1
        s[n]=range(48,57)
    Next
    #endmacro
    #macro compare(n1,n2,ans)
    Scope
        Var lenn1=Len(n1),lenn2=Len(n2)
        If lenn1 > lenn2 Then ans=-1:Goto lbl
        If lenn1 < lenn2 Then ans=0:Goto lbl
        If n1 > n2 Then ans = -1  Else ans= 0
        lbl:
    End Scope
    #endmacro
    Dim As Long L=Len(s1),ans=1
    Dim As String s=String(L,0)
    While ans
        GetNumber
        compare(s,s1,ans)
    Wend
    Return Ltrim(s,"0")
End Function


function rndX overload(s1 as ulongint) as ulongint
    static as ulongint u=18446744073709551615
    return iif(s1=u,Get64Bit(),Get64Bit() mod (s1+1))
end function

function range overload(byref f as string,byref l as string) as string
    return  plus (RndX(minus(l,f)),f)
end function

function range overload(byref f as ulongint,byref l as ulongint) as ulongint
   return RndX((l)-(f))+(f)
end function



dim as ulongint u=18446744073709551615

randomize

for n as long=1 to 20
    print range(u-3,u)
next
print "===================="
for n as long=1 to 20
    print range("184467440737095516150000000000","184467440737095516150000000003")
next


sleep
 
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: DOUBLE's fractional digits to ULONGINT ?

Post by coderJeff »

cbruce, glad you got an answer. paul doe's post is a solid algo. I have been interested in floating point lately and I tried really hard to break the linear interpolation. Best I could do is that the value returned might be a *tiny* bit greater than minimum value if RND() returns zero, and due to conversion error (expected) from decimal constant to floating point representation. As jj2007 points out, floating point is never exact, and when converting between floating point and decimal there are typically errors (expected) in the conversion. So as long as you only use the floating point representation, you should not have any trouble with paul doe's code.

Nit-pick: the notion that floating point fraction could be represented EXACTLY in a ulongint is incorrect: a DOUBLE is an approximation of a decimal number. I don't understand the trip to ulongint in the OP. An analogy for converting floating point to decimal is kind of like converting between number of weeks and number of days; exact sometimes, but mostly not.

if you want to to see exact decimal conversions, I posted at Exact double to decimal conversion
cbruce
Posts: 166
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Re: DOUBLE's fractional digits to ULONGINT ?

Post by cbruce »

'
FYI coderJeff... SWEET converter code !!!
.
Everyone take note... I DON'T need an answer any more! [grin]

I'm just responding to coderJeff here because he is unclear about what (or why) I was asking in the OP.

Note: Most of the verbiage that I used was about "translating" digits between DOUBLEs and ULONGINTs... not "converting" the types. I was just hoping there was a mathy way to accomplish that... as opposed to using strings - (performance issue).

Clarification:

If you have an RNG that works on integers, not doubles (and I do)... and you are a math dummy (and I am).... and people want you to return double values in a specific range (the nerve of some people)... ... ...

Then you might think, "Hey! If I had two integers that were pictures (digit for digit) of the two range double's decimal digits... then I could do a range on those integer values and turn the digits of the resulting random integer back into a picture of a double's digits to return to the silly person that needed a double!"

Code: Select all

0.2897989883, 0.478236622224      'Want a double in this range...

'Str() those and grab just their fractional digits...

'CULngInt() those strings...
2897989883, 478236622224          'Generate a ulongint in this range... (easy with my integer rng)...

349348734897                      'generated RND...

0.349348734897 <== CDbl("0." + Str(349348734897))

And you end up with a double that is guaranteed to be in the requested range!!!

But I didn't want all the STRING stuff... (can anyone say "performance issue"?)
Yes!... It turns out there are (MUCH) simpler ways to get there... I know that now. But I'm just a coder... so I took a hammer to the math that got in my way! [BIG grin]

I'm focused on the PCG RNG, that is based on an LCG, which calculates with and returns integers. The main reason is that an integer LCG allows for the capability of advancing|jumping|skipping back and forth in the sequence stream... a capability that can be extremely useful in a lot of mathy scenarios... and a capability that is not available in an RNG that actually works with floats - (as opposed to using an LCG integer RNG with the output converted to floats).

I hope that makes the OP clearer.

And a HUGE thanks to everyone that responded... perhaps there is a piece of math brain in my head that will kick in before I die.
.
Post Reply