Hi all. Haven't been here for a while.
There is a simple program that takes a real numbers and saves them to file.
By real numbers i mean numbers with dot, for example: 1.2, 3.4, 124.9 etc.
For example the input numbers are
1.0, 0.0, 0.0
When it writes them to file it packs them somehow or swaps and result is this:
00 00 40
If i do a: 40 shr 6
then i get correct value: 1 or anything else that is in that place.
Why 6? Because Bit-Set has 6 zeroes at the right.
Here is a shot:
(http://img187.imageshack.us/img187/2281/saving1.png) (http://img187.imageshack.us/i/saving1.png/)
When something else is used instead of zeroes at the right, for example:
1.2, 0.0, 0.0
Things get complicated, it saves this like so:
00 CC 4C
Here is a shot:
(http://img683.imageshack.us/img683/2042/shot2sav.png) (http://img683.imageshack.us/i/shot2sav.png/)
Im always watching that Bit-Set binary data in that window.
The problem is that i don't get it how it packs the numbers in that case?
Also it flips the bytes: it should be 4C CC which is 19660 in decimal and 01001100 11001100 in binary. Which is (16bit) 2 bytes (a WORD)
0.1 is saved like this: 66 06
Assembler gurus here, tell me how the real numbers are saved?
If i could at least pack the real numbers to get same bits then unpacking just would basically be reverse of this.
Something is probably ANDed, XORed and maybe ORed and then shifted.
I need to unpack the data and later again pack.
Any help is greatly appreciated.
i don't know if they are using intel standard real format - they may be (it would seem convenient)
i didn't evaluate the numbers you posted to see
but, here is a site that has the info...
http://www.ray.masmcode.com/tutorial/fpuchap2.htm
they look like they might be "real4" values - 4 byte reals
Quotethey look like they might be "real4" values - 4 byte reals
That is impossible. The ".2" decimal fraction is not an exact multiple of fractional powers of 2 and bits would be set in all 4 consecutive bytes of a REAL4. His 1.2 would look more like 3F99999A according to the IEEE format of REAL4 floating points.
BytePtr must provide some additional information on what is generating those displayed numbers if he expects an answer.
well - that's what i said - i didn't take the time to evaluate the numbers he posted
but, the format may be similar - at least it gives him a place to start
the thing is, he has posted only a few values
to reverse-engineer the format would require several more values as examples
and, even then, you might not have it right
it shouldn't be all that hard to find the ms word file format defintion
keep in mind that the format may be from ms excel, instead - you may want to search for that file definition also
that could save you a lot of headaches and wasted effort
Thanks for replies. The numbers above are just examples. User can use any number in range of 0.0 to 255.8
And it's not Excel or any such app.
It's a game scripting compiler tool that takes user scripts that parses them with Lexx or Yacc and generates compiled script.
Compiled scripts are always 80.7KB in size. This is what game uses.
And unfortunately the specs are not available. They were never released.
Seems that this compiler detects if number after dot is greater than 0, if it is then it uses some other methods to save the numbers and if the number after dot is 0 then it saves the real number as integer.
At least it seems so.
But the fact is: dot must always present in number. Otherwise compiler throws an error.
Hi,
Plugging the (little endian) numbers in a calculator, it seems
that you have fixed point numbers, not floating point. At least
they sure look that way, given the examples.
Regards,
Steve N.
Yeah fixed point for sure.
I don't think that they made this so complex by using floating point. No.
The numbers after dot are just for adjusting, so they can handle things more precisely.
well - we don't call that "flipping" - lol
for us, it is normal for higher-order bytes of values to have higher addresses (called "little-endian", as opposed to "big-endian")
but - the 255.8 clue doesn't help much
the reason is, that could be stored as a 16-bit integer of 2558
that tells me that the format probably allows larger values than 255.8, and/or more than 2 decimal places (25580 also fits into 16 bits)
the problem you may have is describing special values like infinity, if it allows it and other special values
and - how does the program recognize whether it is stored as an integer or a real ?
the answer to that is: it is likely that the format is the same - i.e. values under 256 with no decimals just happen to be integers
if you look at Ray's tutorial i linked above, you will see some characteristics that may help you
that is, the general form in how real numbers are stored
in the case of intel reals, there is a sign bit, some number of exponent bits, and some number of mantissa bits
i do see a pattern with which i am familiar
that is the CCCCC pattern (in binary, that's ...110011001100...)
that pattern results when you divide a binary orthogonal (like 65536 or 4294967296) by 10
It maybe allows larger values but they are never used.
Everything is limited to user. Nothing can be infinite in scripting, that's for sure. Scripting manual also tells that.
Otherwise game will crash and access violation occurs.
The game itself is limited to 256x256x8 area. The real numbers i posted are the coordinates.
I will try more different numbers and see what it generates from them.
in "4CCCh", the bit from the 4 may be the "1.0" part and the CCC bits may be the "0.2" part (2/10)
QuoteThe game itself is limited to 256x256x8 area.
well - there is more to it than that, if you have a number like 1.2 or 255.8, then the real grid is something like 2558 x 2558 x 78
perhaps they are storing the three coordiantes as seperate integers
you need to make a table of values
0.0
0.2
0.4
0.6
0.8
1.0
1.2
.
.
10.0
12.0
and so on - do enough decades until you see the pattern
Hi,
To elaborate, given the examples:
Given Hex Dec Binary
1.0 => 4000H => 16384 => 100110011001100B
1.2 => 4CCCH => 19660 => 100000000000000B
0.1 => 0666H => 1638 => 11001100110B
You (apparently) have a fixed point number created by
multiplying a real number by 16384 and saving the integer
part.
HTH?
Steve
enter the maximum 3D coordinate 255.8, 255.8, 7.8 - or whatever it is
show us that representation
EDIT - looks like Steve is on the right track :U
(http://img502.imageshack.us/img502/1816/maximumbit.png) (http://img502.imageshack.us/i/maximumbit.png/) (http://img502.imageshack.us/img502/maximumbit.png/1/w798.png) (http://g.imageshack.us/img502/maximumbit.png/1/)
I entered. (255.7, 255.7, 7.7).
Because 0 is also used. So: 0-255 = 256 and 0-7 = 8.
Steve:
Well it seems that you are correct. I took one simple real number like 1.0 and multiplied it with the number: 1.0 * 16384 and really got the same value as in the compiled script.
But more tests must be done. To be sure. I will try more numbers. But i think that this is it.
yup - Steve got it - take the real, mul by 16384 and round to the nearest whole integer
Thanks alot dedndave and Steve.
But what is the reverse of this? I know how the values are saved now but how to get the values from them?
Pure "bitwork" now ? SHR'ing and other such things?
that is fairly simple
to convert from decimal to file format:
i would remove the decimal (255.7 -> 2557), multiply it by 16384 (SHL 14), then divide by 10 and round (add one if remainder >4)
ater you are done rounding, you will want to compare the result to the max of 3FECCCh, and set the max if over
Thanks. I will try.
Will let you know.
mov eax,Decimal_Value_x10 ;2557 max
shl eax,14
xor edx,edx
mov ecx,10
div ecx
cmp edx,ecx
cmc
adc eax,0
cmp eax,3FECCDh ;max result + 1
cmc
sbb eax,0 ;result in eax
well, that's one way - lol
Yep this works. Thanks.
But now final thing.
Getting real values from the bits saved in file.
Example:
App saved 51.4. Result is 0CD99 in hex. This hex value is in file now.
Let's say i need to get that value: 51.4 from the file.
How that should be done?
Pretty much of it probably would be reverse of the saving the bits? But i am sure that something else must be done.
To get the real values from the HEX again.
Drop me at least some algorithm and i will try code that. I will learn something from it that way.
assuming you want an ASCII decimal string...
the result is little-endian (AL = first digit)
you will have to add the decimal point in, yourself (decimal point = 2Eh)
mov eax,Value_From_File ;3FECCCh max
mov edx,10
mul edx ;edx becomes 0
shr eax,14
adc eax,edx ;2557 max result
mov ecx,100
div ecx
aam
bswap eax
mov ax,dx
aam
xchg al,ah
or eax,30303030h ;make it ASCII numeric
oops - i think i re-arranged the digits :bg
let's try that again...
mov eax,Value_From_File ;3FECCCh max
mov edx,10
mul edx ;edx becomes 0
shr eax,14
adc eax,0 ;2557 max result
mov ecx,100
div ecx
aam
xchg eax,edx
aam
bswap eax
mov al,dh
mov ah,dl
or eax,30303030h ;make it ASCII numeric
Well, this piece of code:
mov eax,0160h ;3FECCCh max
mov edx,10
mul edx ;edx becomes 0
shr eax,6
works and returns me the correct value without "dot". I changed shr eax, 14
to shr eax,
6
The rest of it doesn't work for me.
I haven't used ASM for a while now and seems that i have forgot many things. Now i am trying to get my hands again on it.
You said ASCII numeric string. You stored these 2 number in AL and AH?
And now they are represented as ASCII characters?
Correct? Why i am unable to display them then?
well - shr eax,6 does not do the same thing as shr eax,14 - lol
look at my previous posts - i did update that last routine, as i made a mistake first time around :bg
the result is 4 ASCII numeric characters in eax, the left-hand digit is in AL, second in AH, and so on
i did not supress leading zeros or place the decimal - i leave that stuff to you
I know that changing shr 14 to shr 6 doesn't do the same thing.
Don't think that im so noob in asm.
Im not, just haven't used asm for a while now and forgot many things.
I changed it to shr 6 because this way the snippet
mov eax,0160h ;3FECCCh max
mov edx,10
mul edx ;edx becomes 0
shr eax,6
worked for me fine then. The rest of your code makes ASCII out of the numbers?
Correct?
Now i used your fixed code as is and messed around with it.
First i put 0660h (25.5) into EAX and then tried to print out the value:
mov eax,0660h ;3FECCCh max
mov edx,10
mul edx ;edx becomes 0
shr eax,14
adc eax,0 ;2557 max result
mov ecx,100
div ecx
aam
xchg eax,edx
aam
bswap eax
mov al,dh
mov ah,dl
or eax,30303030h ;make it ASCII numeric
print str$(eax),13,10
Result is 825241648. Are they ASCII numeric character codes?
Or im heading in totally wrong way?
If i just: "print eax, 13,10" then program crashes.
13,10 (CR,LF) is not needed but im using them alot.
well - part of the code converts the value to a binary number from 0 and 2557
we multiply by 10, then shift right 14 bits to divide by 16384
at the end of that shift, we round the result with adc eax,0
if the highest bit that was shifted off is a 1, it increments the result
if the highest bit that was shifted off is a 0, it does not increment the result
mov eax,Value_From_File ;3FECCCh max
mov edx,10
mul edx ;edx becomes 0
shr eax,14
adc eax,0 ;2557 max result
the next part splits that binary value into 4 seperate decimal digits
mov ecx,100
div ecx
aam
xchg eax,edx
aam
bswap eax
mov al,dh
mov ah,dl
at that point, there are 4 binary digits in EAX, each one in a seperate byte
the first digit is in AL (high order digit)
if you just want to store the 4 binary digits
mov dword ptr Stored_Bytes,eax ;Stored_Bytes is 4 bytes
if you want them to be ASCII numeric digits
or eax,30303030h ;make it ASCII numeric
mov dword ptr Stored_Bytes,eax
the problem you are having with the print macro is that "print eax" displays the zero-terminated string at the address in eax
if you want to see what is in eax, try this...
Stored_Bytes db 4 dup(?),13,10,0
.
.
or eax,30303030h ;make it ASCII numeric
mov dword ptr Stored_Bytes,eax
print offset Stored_Bytes
if you want to view it in hexidecimal, this will work
print uhex$(eax),13,10
the uhex$ macro creates the zero-terminated string and passes its address to the print macro
Ohh, "offset", "dword ptr" all that stuff. Of course. Totally forgot them.
I used them in my 16bit asm programs.
Will take my fat asm books from my bookshelf and will read them again.
Seems that i forgot alot of important stuff.
Thanks Dave.
I will let you know how it goes.
dedndave or anybody.
I need your help again.
Let's say i have a 3 values like: (0.0, 2.0, 2.0)
In file, this is 2.0 saved like 0x8000, as hex.
The tool generates a .tmp file with values like these: (0,131072,131072)
What this could mean? They should be DWORD's, but im not sure.
I really would like to know, what they mean, is it possible to figure out, how is 2.0 related to 131072?
The numbers are fixed point always. Not floating.
Thanks.
Quote from: BytePtr on October 15, 2011, 01:13:22 PMI really would like to know, what they mean, is it possible to figure out, how is 2.0 related to 131072?
131072 = 0x20000
Maybe: 16 Bit for pre-decimal point positions and 16 bit for decimal places?
<0x2>.<0x0000>f
yah - you really haven't given us enough information to work with
there are many possible formats the might store 2.0 as 8000h
maybe you can show us how more values are stored
can it be negative ? - show us how some negative values are stored
what is the maximum value ? - show us how that is stored
what is the minimum value ? - show us how that is stored
show us how 0.0, 0.5, 1.0, 1.5 are stored
I did a quick test to see if the stored values might be half-precision floating-point numbers, but in that format 2.0 is 4000h.
http://en.wikipedia.org/wiki/Half_precision
it could be as simple as 2 bits ahead of the DP and 14 bits after
xx.xxxxxxxxxxxxxx
the range would be 0 to +3.99993896484375 (which is 3 + (16383/16384))
Solved this problem, by using typecasting to "WORD" and "shr 16"
To get higher and lower values packed in DWORD.
I don't know why, but it worked for me.
I have alot to learn.
QuoteThe numbers are fixed point always. Not floating.
If the "tool" he is using is the MixLib library for fixed point math ( http://www.ray.masmcode.com/fixmath.html ), he would be getting 20000h for 2.0. BytePtr was probably correct.
Hi again all.
I have a DWORD32 (unsigned int). The value i will hold in this is maximum: 526271.
Also i would like to store single digit in it, just one of the: 0, 1, 2, 3, 4.
The big number max is 526271 as i said, but it changes (could be even 0), same with single small number, it could be anything from 0 to 4.
Is it possible somehow pack this info together and later also unpack the big number and this single digit, without data loss?
TIA
No problem...
include \masm32\MasmBasic\MasmBasic.inc ; download (http://www.masm32.com/board/index.php?topic=12460)
Init
mov eax, 4 ; Factor A
shl eax, 28
mov ebx, 526271 ; Factor B
or ebx, eax ; A or B
nop
mov eax, ebx ; read Factors
sar eax, 28 ; shift out B
Print Str$("Factor A=%i\n", eax)
mov eax, ebx ; read Factors
and eax, 1111111111111111111111111111b ; isolate A
Print Str$("Factor B=%i\n", eax)
Inkey "ok"
Exit
end start
Factor A=4
Factor B=526271
I started to read this:
http://webmasters.physics.upatras.gr/mirrors/assembly/Page_AoA/4_5.pdf
And even tried to code out something, but not the way you did it.
I wish i could throw out code like this in a seconds.
Thanks alot jj2007. I will credit you for this.