Request: Double data typesBlitz3D Forums/Blitz3D Bug Reports/Request: Double data types
| I'm guessing the reason doubles were never added to b3d or b+ was because it is a non-trivial task. But just in case it was for some other reason I am requesting native double data types for Blitz3D. There is a dll made by a user here which allows double conversion but this won't work with other dll's that have functions with doubles as parameters, rendering them useless.|
I suggest the following syntax for doubles:
Thanks for your time.
| I also want doubles, because I need them for converting fractionals with more precision. |
| I have to add a correction to this post. I have recently discovered it is possible to pass a double as 2 integers to a function in a dll with a double parameter. This was figured out ages ago actually for OpenGL functions. |
I have to add a correction to this post. I have recently discovered it is possible to pass a double as 2 integers to a function in a dll with a double parameter. This was figured out ages ago actually for OpenGL functions.
That could come in handy. What's the syntax for doing that, markcw? Do you just add the singles together in the dll function call (eg. ExampleDllFunctionCall( singlevar1 + singlevar2 ))?
| This should explain it.|
| Thanks for the info. |
| I couldn't find a DblToSng function anywhere. This might work but is untested.|
Edit: Well it looks like it does work going by this simple test, although it's not incredibly accurate it is sufficient.
| I fixed the accuracy problem and have made a module:|
The problem was this line:
Sfract = ((DH And 1048575) Shl 3) + (DL Shr 28)
Should have been this:
Sfract = ((DH And 1048575) Shl 3) + (DL Shr 29)
| markcw, incidentally, just wondering if this thread would draw your attention to a problem that I found converting floats to a string: http://www.blitzbasic.com/Community/posts.php?topic=71385#798197|
I still haven't got the perfect routine to do so, and would really be grateful for help on this one. I still don't have the perfect routine for this. The goal in the end is to have the ascii codes stored in a bank, and of course the issue is to have a speedy way of doing this, not use string conversion operations.
| I don't see what the problem is, all the numbers in the test were as expected. |
| markcw, I know that's because the for loop was generating a number that the function liked. Try this for loop instead:|
For i# = -125.0 To 125.0 Step 15.7
| Yeah, I thought that after posting. Where'd you get this code from? Might help. |
| Oh I tried many attempts at it. It is my code. I have many other routines to convert floats to ascii byte values, but they all give innacurate values due to some problem on how floats are handled in blitz. Also the reason why I use my routine instead of string manipulation and so on is because I work with banks (for a script language parser I made). |
| Well I had a go but nothing yet. I did however, after some reading, discover how to calculate a float from an integer, and then I found some code to do the reverse. So I added these to my Float2Double module as Float2Int and Int2Float. |
| See here, I can't properly isolate the values after the decimal point. Blitz returns unusual, results, and there is no function I know in blitz to get only the fraction part of a number:|
For i# = -125.0 To 125.0 Step 14.554 ln = write_FLOAT(i) Next WaitKey() Function write_FLOAT%(num_in#) Local num_upper% = Floor(num_in) Local num_lower% = (num_in - Float num_upper) * 100000.0 Write num_upper + "." + Abs(num_lower) End Function
In this case, it starts to break the value after 4 decimals...
See the problem in blitz is there is no reliable function that return the fraction portion of a number. If I had that, it would probably make my life easier for what I need to accomplish.
Here is how I try to study the float values from a binary standpoint:
Graphics 1024,768,32,2 Print " 1 = " + Bin$(Get_Float_Content(1)) Print " -1 = " + Bin$(Get_Float_Content(-1)) Print " 2 = " + Bin$(Get_Float_Content(2)) Print " -2 = " + Bin$(Get_Float_Content(-2)) Print " 3 = " + Bin$(Get_Float_Content(3)) Print " -3 = " + Bin$(Get_Float_Content(-3)) Print " 1.1 = " + Bin$(Get_Float_Content(1.1)) Print " 1.2 = " + Bin$(Get_Float_Content(1.2)) Print " -1.2 = " + Bin$(Get_Float_Content(-1.2)) Print " 1000 = " + Bin$(Get_Float_Content(1000)) Print " -1000 = " + Bin$(Get_Float_Content(-1000)) Print " 65535 = " + Bin$(Get_Float_Content(65535)) Print " 65536 = " + Bin$(Get_Float_Content(65536)) Print " 65536.1 = " + Bin$(Get_Float_Content(65536.1)) Print "131072.1 = " + Bin$(Get_Float_Content(131072.1)) Print "262144.1 = " + Bin$(Get_Float_Content(262144.1)) Print " 524288 = " + Bin$(Get_Float_Content(524288)) Print " 1048576 = " + Bin$(Get_Float_Content(1048576)) Print "1048576.1= " + Bin$(Get_Float_Content(1048576.1)) Print "1048576.2= " + Bin$(Get_Float_Content(1048576.2)) Print "1048576.3= " + Bin$(Get_Float_Content(1048576.3)) Print "1048576.4= " + Bin$(Get_Float_Content(1048576.4)) Print "2097152.4= " + Bin$(Get_Float_Content(2097152.4)) Print "2097152.6= " + Bin$(Get_Float_Content(2097152.6)) WaitKey() Function Get_Float_Content%(value#) Local fb% = CreateBank(4) PokeFloat(fb,0,value) ret% = PeekInt(fb,0) FreeBank(fb) Return ret End Function
Detail on the composition of a float: http://steve.hollasch.net/cgindex/coding/ieeefloat.html
| Would this help you?|
Edit: see below.
| So, with this, it is possible to get the whole, and the fraction :P Very nice coding markcw, surprisingly simple and efficient!|
EDIT: The only drawback I found is the usage of the value#^value% which is rather very slow when interpreted in bliltz. So, I managed a small efficient Exp10 routine to go with your function :P Just toss in the multiplier, and it will return the multiply factor.
Function Exp10#(value%) ; about 8 times faster than 10^value Select value Case 0 : Return 1.0 ; 10^0 Case 1 : Return 10.0 ; 10^1 Case 2 : Return 100.0 ; 10^2 Case 3 : Return 1000.0 ; 10^3 Case 4 : Return 10000.0 ; 10^4 Case 5 : Return 100000.0 ; 10^5 Case 6 : Return 1000000.0 ; 10^6 Case 7 : Return 10000000.0 ; 10^7 Case 8 : Return 100000000.0 ; 10^8 Case 9 : Return 1000000000.0 ; 10^9 End Select End FunctionBasically you'd say:
Return Fraction / Exp10(FractionPart)
| Er, thanks but I forgot about very big and very small values and a few other things. So while that code looks right there are bugs. The good news is that I've fixed it.|
just found and fixed another bug. I think that's it now but I'm not sure.
another change, removed a bit that wasn't needed.
last edit, fixes a rounding error and adds a cheat if less than 1.
Edit: see below.
| markcw, is it me or is FractionPart giving out some irregularities? |
| Nope, it's not you. There are still some bugs with this code and I'm trying to fix them. You can see the problem if you get random values in a loop and string compare with the fraction until you get an error. The problem with FractionPart is that when you subtract the whole - floor(whole) you don't get the exact fraction, you get an approximation which means sometimes FractionPart will be quite inaccurate. I'm not sure what to do about it yet. |
| markcw, I got good and bad news about single precision. The good news is I found some good web document about the internals. The article has a C code example which does something that I need. I converted it to Blitz code. The bad news is, I have an imprecision in the fractions, yet again!!!! And it sounds like the same problems that we have generally speaking. The example code follows, and notice my debug prints ;) HINT: The first frac should of been 16384|
pf (-772.1) WaitKey() End Function pf(x#) Print "float = " + x Local fb% = CreateBank(4) PokeFloat(fb,0,x) xx% = PeekInt(fb,0) sign% = xx Shr 31 expo% = ((xx Shr 23) And $ff) - $7F man% = (xx And ((1 Shl 23) - 1)) And $7FFFFFFF ; I removed the sign bit here (maybe pointless) man% = man Or (1 Shl 23) s$ = "" If sign = 1 Then s$ = "-" Print s$ + (man Shr (23 - expo)) + "." frac% = man And ((1 Shl (23 - expo)) -1) base% = 1 Shl (23 - expo) : Print "base:" + base c% = 0 While (frac > 0 And c < 6) c = c + 1 frac = frac * 10 : Print "frac:" + frac Print (frac / base) frac = frac Mod base Wend FreeBank(fb) End Function
| Well, I have another version of FloatFraction here. This one may be slightly better but it still isn't 100% accurate. The thing about floats is that they aren't exact, they're a close approximation, so I don't think you're ever going to get exactly what you want. I'm finished with this effort, I don't want to spend any more time on it.|
Edit: see below.
| Well I somehow have managed to prove myself wrong, again, because I appear to have a version that is 100% accurate. It's a little slower but worth it. I found a way to isolate the wrong values and then round up in these rare cases.|
Edit: see below.
| Another update to FloatFraction, hopefully the last one. I fixed a bug in the wholepart loop that I created. I also am not returning stuff before the end any more as that doesn't really help.|
Edit: see below.
| still not 100%, but thumbs up for the effort. |
| Could you elaborate perhaps? |
| When I run this last one, I get roughly 1500 errors on a 100 000 run. I have no clue why! Tell me it's not because I have an AMD. I'm using Blitz3D v1.99. By the way, I want to know if you have run the small sample I posted earlier, see if you get errors in the conversion. |
| The errors in the test loop should actually be correct, it's just that the string compare method can't handle the exponent form. |
| Yeah, you're right Jacques, there are still errors. It's with numbers less than 1. I had a cheat in where if WholePart was zero then just return Abs(Value#) but then I realized this wouldn't really help if you want to get the exact value so I took it out. I'll try to fix it. |
| Hey there Mark, here is a little something I did. I got my own version of the FloatFraction running in there which is a very optimized version of one of your early tries. I got a performance bench and a trial error test also. Enjoy!|
| Well, I have a new function, this once's my favorite because it's not so ugly. It won't work for values smaller than 1.0e-004 so I cheat after that and just return Abs(value#). I couldn't fix the inaccuracies in these very small values, but none of the other versions could do this anyway. If you get any errors let me know what range they're in.|