在C ++上加倍:它们如何工作为什么会出现“精确错误”,为什么编译器会将其视为DWORDS? [英] doubles on C++ :how do they work why is there a "precision fault",and why are some treated as DWORDS by the compiler?

查看:71
本文介绍了在C ++上加倍:它们如何工作为什么会出现“精确错误”,为什么编译器会将其视为DWORDS?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我宣布:

double d=2644;
double as=24.166496

然后,使用ollydebug检查程序的内存内容。

程序正在使用一个奇怪的(对我来说)方法来写这个使用FLD和FSTP指令编号到内存。

与两个c ++命令相对应的汇编代码是

and then,using ollydebug examine the memory contents of the program.
the program is using a strange (to me ) method to write this number to the memory using the FLD and FSTP instructions.
the assembly code coresponding to the two c++ commands is

FLD DWORD (source)
FSTP QWORD (destination)
FLD QWORD (source)
FSTP QWORD (destination



为什么第一个变量首先被视为DWORD并且在QWORD之后(前两个命令)??

也是,d变量在内存中是0x40a4a80000000000。

当存储值2643时内存是0x40a4a60000000000

如何将fpoint数转换为二进制数?

我认为这是多余的但它看起来不像。

最后,存储在ST0堆栈中的数字是2644.0000000000015000。

它的十六进制表示是400AA540000000000000

为什么它不是简单的2644.0,为什么值在ST0不同于内存?

谢谢!


why is the first variable treated as a DWORD at first and at QWORD later (first two commands) ??
also,the d variable is 0x40a4a80000000000 in memory.
when storing the value 2643 the memory is0x40a4a60000000000
how is the fpoint number converted to binary ?
I thought it was an excess but it doesnt seem like it.
finally,the number stored in the ST0 stack is 2644.0000000000015000 .
and it's hex representation is 400AA540000000000000
why isn't it simply 2644.0 and why is the value at ST0 different than that of memory ?
thank you !

推荐答案

1。因为您只需要一个16位字(或更准确地说,12位)来存储数字2643.但是,当使用与操作环境的本机字大小匹配的字大小时,内存访问会更快。因此,最好加载一个容纳2643的4字节int,而不是加载2'(或任何其他值)字节int。 (在32位模式下操作时)



2.该数字由fpu以IEEE 754格式存储。您可以在维基页面上阅读更多相关信息(IEEE754),或者您认为更适合您需求的任何其他内容。 http://en.wikipedia.org/wiki/IEEE_floating_point [ ^ ]



3.因为你无法代表全部精确浮点数。有些你可以准确地表示 - 其他你可以用很小的错误代表。显示2644.0000000000015000的情况下的错误(1000亿中的15个部分)太大 - 在大多数情况下,这是一个非常微不足道的数量。这相当于大约10万立方米水的3茶匙水。



3b。 OllyDbg知道加载到ST0的内容,因此显示了他的值,而不是寄存器中保存的确切值,从而以明确的方式向反向工程师/调试器显示意图。





#3是我们不用浮点数代表货币的原因 - 它们与它们固有的不准确。
1. Because you only need a 16 bit word (or more accurately, 12 bits) to store the number 2643. However, memory access is faster when using a word-size that matches the native word size of the operating environment. So, it's better to load a 4-byte int that holds 2643 than it is to load a 2 '(or any other value) byte int. (when operating in 32 bit mode)

2. The number is stored by the fpu in IEEE 754 format. You can read more about it (IEEE754) on the wiki page,or any other you find better suited to your needs. http://en.wikipedia.org/wiki/IEEE_floating_point[^]

3. Because you can't represent all floating point numbers precisely. Some you can represent exactly - others you can represent with a small degree of error. The error in the case you show 2644.0000000000015000 is (15 parts in 100 billion) too large - an entirely trivial amount is most circumstances. This is equivalent to 3 teaspoons of water too much in an order of 100,000 cubic meters of water.

3b. OllyDbg knows what was loaded into ST0, and so displays his value, rather that the exact value held in the register, thus indicating intent in a clear manner to the reverse-engineer/debugger.


#3 is the reason that we don't represent money with floating point numbers - their is in inherent inaccuracy with them.


With FPU命令, DWORD QWORD 表示存储在内存中的数字的类型(单精度或双精度)。在您的情况下,编译器决定以单精度存储数字2644。



FLD 命令将从内存加载数字,将其转换为内部使用的80位双扩展精度格式化,并将其推送到FPU堆栈。 FSTP 命令会将堆栈顶部的值转换为内存大小指定的类型,将其存储到内存中,然后弹出堆栈。



您现在可能想知道为什么编译器使用FPU命令而不是压缩内存内容。在这里使用FPU命令减少了数据存储器(使用4个字节而不是8个字节存储一个值)以及32位应用程序的程序存储器(使用两个FPU命令比复制两个64位值需要更少的代码)。它也更快,因为FPU命令独立于正常CPU指令执行(只要不需要FPU和CPU之间的同步,这由 FWAIT 指令执行)。如果启用SSE / SIMD扩展的使用,编译器也可以使用它们来复制浮点值。



比较内存中读取原始十六进制数据的数字,你必须知道格式并自己转换数字,如果它们没有相同的精度。



一些好的读数是:

维基百科IEEE浮点数 [ ^ ]文章。

英特尔®64和IA-32架构软件开发人员手册 [ ^ ]:

第1卷,第4章,第4.2.2节:浮动 - 点数据类型

第1卷,第8章:使用X87 FPU进行编程。

第2卷包含指令集参考,包括FPU命令。
With FPU commands, the DWORD and QWORD indicate the type of the number stored in memory (single or double precision). In your case the compiler decided to store the number 2644 in single precision.

The FLD command will load the number from memory, convert it to the internally used 80 bit double extended precision format, and push it onto the FPU stack. The FSTP command will convert the value on top of the stack to the type specified by the memory size, store it to memory, and pop the stack.

You may now wonder why the compiler uses FPU commands rather than coyping memory content. Using the FPU commands here reduces data memory (storing one value using 4 bytes instead of 8 bytes) and also program memory for 32 bit applications (using two FPU commands requires less code than copying two 64 bit values). It is also faster because FPU commands are executed independently of normal CPU instructions (as long as no synchronization between FPU and CPU is required which is performed by the FWAIT instruction). If you enable usage of SSE/SIMD extensions, the compiler may also use these to copy floating point values.

To compare numbers in memory reading the the raw hex data, you must know the format and convert numbers yourself if they did not have the same precision.

Some good readings are:
Wikipedia IEEE floating point[^] article.
Intel® 64 and IA-32 Architectures Software Developer Manuals[^]:
Volume 1, Chapter 4, Section 4.2.2: Floating-Point Data Types
Volume 1, Chapter 8: PROGRAMMING WITH THE X87 FPU.
Volume 2 contains the instruction set reference including the FPU commands.


这篇关于在C ++上加倍:它们如何工作为什么会出现“精确错误”,为什么编译器会将其视为DWORDS?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆