- 主题:软件bug么
下面这段代码:
float a = 1.8;
int b = 110 * a / 11;
在 visual studio 2005下面 32位编译时 b的值为17。
换成64位编译为18。
--
FROM 223.104.211.*
看汇编代码
--
FROM 125.35.121.*
x86 debug:
pushebp
movebp, esp
subesp, 216; 000000d8H
pushebx
pushesi
pushedi
leaedi, DWORD PTR [ebp-216]
movecx, 54; 00000036H
moveax, -858993460; ccccccccH
rep stosd
fld DWORD PTR __real@3fe66666
fstp DWORD PTR _a$[ebp]
fld DWORD PTR _a$[ebp]
fmul QWORD PTR __real@405b800000000000
fdiv QWORD PTR __real@4026000000000000
call __ftol2_sse
mov DWORD PTR _b$[ebp], eax
x86 release:
push 17 ; 00000011H
push OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@
【 在 z16166 的大作中提到: 】
: 看汇编代码
--
修改:grainbuds FROM 101.80.114.*
FROM 101.80.114.*
刚在VS2019跑了一下,不管Release/Debug/32/64 输出结果都是18
【 在 grainbuds 的大作中提到: 】
: 下面这段代码:
: float a = 1.8;
: int b = 110 * a / 11;
: ...................
--
FROM 222.129.54.*
因为VS2005用的是基本浮点指令的问题吧
单步跟进_ftol2_sse()这个内部看最终执行的是什么"浮点 -> 整数"的转换指令,如果是cvttsd2si,结果就是17。
VS2019用的是SSE指令,和基本浮点指令的计算精度可能不同。这个网站直接能看汇编
https://godbolt.org这个截图是把你的指令扒出来单步调试的结果。
【 在 grainbuds 的大作中提到: 】
: x86 debug:
: push ebp
: mov ebp, esp
: ...................
--
修改:z16166 FROM 125.35.121.*
FROM 125.35.121.*
哦,学习了
【 在 z16166 (Netguy) 的大作中提到: 】
: 因为VS2005用的是基本浮点指令的问题吧
: 单步跟进_ftol2_sse()这个内部看最终执行的是什么"浮点 -> 整数"的转换指令,如果是cvttsd2si,结果就是17。
:
: VS2019用的是SSE指令,和基本浮点指令的计算精度可能不同。这个网站直接能看汇编
--
FROM 101.80.114.*
和寄存器指令有关最开始。
最开始浮点数都是fpu计算,fpu寄存器都是80bits大小,不管float还是double,没有区别,指令也一样。
后来2000年前后,intel推广sse,引入xmm寄存器,遵从float/double的大小,使用不同的指令。这时的float才是真float。
所以fpu精度高,性能差。sse精度低,但性能高。
从vs2013开始,全部使用sse指令。之前版本x86使用fpu,x64使用sse。
这只是告诉你为啥x86和x64为啥不一致, 至于为何一个是17一个是18就需要看intel实现了。
另外,由于都使用sse,所以尽量用float计算,比double快了很多。
【 在 grainbuds 的大作中提到: 】
: 下面这段代码:
: float a = 1.8;
: int b = 110 * a / 11;
: ...................
--来自微水木3.5.11
--
FROM 140.206.195.*
求解惑,double 与 float 的运算速度测试,为什么是这样?
重复执行4次一样的代码,只有第一次的时候,double与float有明显区别,后面三次区别就很小了
#include <iostream>
#include <math.h>
#include <chrono>
using namespace std;
class TicToc
{
public:
TicToc(const std::string& name):m_name(name) { tic(); }
void tic() {
start = std::chrono::system_clock::now();
}
void toc() {
auto millinon_second = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now()-start);
std::cout << m_name << " cost " << millinon_second.count() << " ms." << std::endl;
}
private:
std::string m_name;
std::chrono::time_point<std::chrono::system_clock> start, end;
};
constexpr size_t N = 20000000;
double result_double[N];
float result_float[N];
int main()
{
float pi_float = 3.1415926f;
double pi_double = 3.1415926;
TicToc double_time("double multiply ");
for (size_t i = 0; i < N; ++i) {
result_double[i] = double(i) * pi_double;
}
double_time.toc();
TicToc float_time("float multiply ");
for (size_t i = 0; i < N; ++i) {
result_float[i] = float(i) * pi_float;
}
float_time.toc();
/////////////////////////////////////////
TicToc double_time2("double multiply 2");
for (size_t i = 0; i < N; ++i) {
result_double[i] = double(i) * pi_double;
}
double_time2.toc();
TicToc float_time2("float multiply 2");
for (size_t i = 0; i < N; ++i) {
result_float[i] = float(i) * pi_float;
}
float_time2.toc();
/////////////////////////////////////////
TicToc double_time3("double multiply 3");
for (size_t i = 0; i < N; ++i) {
result_double[i] = double(i) * pi_double;
}
double_time3.toc();
TicToc float_time3("float multiply 3");
for (size_t i = 0; i < N; ++i) {
result_float[i] = float(i) * pi_float;
}
float_time3.toc();
/////////////////////////////////////////
TicToc double_time4("double multiply 4");
for (size_t i = 0; i < N; ++i) {
result_double[i] = double(i) * pi_double;
}
double_time4.toc();
TicToc float_time4("float multiply 4");
for (size_t i = 0; i < N; ++i) {
result_float[i] = float(i) * pi_float;
}
float_time4.toc();
}
编译: g++ float_double.cpp -std=c++11 -O3
四次运行结果:
xxxx$ ./a.out
double multiply cost 73 ms.
float multiply cost 28 ms.
double multiply 2 cost 11 ms.
float multiply 2 cost 9 ms.
double multiply 3 cost 11 ms.
float multiply 3 cost 14 ms.
double multiply 4 cost 14 ms.
float multiply 4 cost 14 ms.
xxxx$ ./a.out
double multiply cost 51 ms.
float multiply cost 28 ms.
double multiply 2 cost 12 ms.
float multiply 2 cost 9 ms.
double multiply 3 cost 11 ms.
float multiply 3 cost 14 ms.
double multiply 4 cost 14 ms.
float multiply 4 cost 14 ms.
xxxx$ ./a.out
double multiply cost 51 ms.
float multiply cost 28 ms.
double multiply 2 cost 11 ms.
float multiply 2 cost 9 ms.
double multiply 3 cost 11 ms.
float multiply 3 cost 14 ms.
double multiply 4 cost 14 ms.
float multiply 4 cost 14 ms.
xxxx$ ./a.out
double multiply cost 78 ms.
float multiply cost 28 ms.
double multiply 2 cost 11 ms.
float multiply 2 cost 9 ms.
double multiply 3 cost 11 ms.
float multiply 3 cost 14 ms.
double multiply 4 cost 14 ms.
float multiply 4 cost 13 ms.
平台:Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
【 在 foliver 的大作中提到: 】
: 和寄存器指令有关最开始。
: 最开始浮点数都是fpu计算,fpu寄存器都是80bits大小,不管float还是double,没有区别,指令也一样。
: 后来2000年前后,intel推广sse,引入xmm寄存器,遵从float/double的大小,使用不同的指令。这时的float才是真float。
: ...................
--
FROM 14.155.19.*
多谢,我测试了一下,使用fpu,1.8变成了1.7999999523162841,乘完110 之后变成了197.99999475479126,再除以11后就是17.999999523162841,最终取整就成了17。
而使用sse后乘的结果是198.0。
【 在 foliver (Oliver) 的大作中提到: 】
: 和寄存器指令有关最开始。
: 最开始浮点数都是fpu计算,fpu寄存器都是80bits大小,不管float还是double,没有区别,指令也一样。
:
: 后来2000年前后,intel推广sse,引入xmm寄存器,遵从float/double的大小,使用不同的指令。这时的float才是真float。
--
FROM 223.104.211.*
应该是你那两个数组缓存导致的。
你在测试之前,先用循环把那两个数组赋值一下。
【 在 confinement 的大作中提到: 】
: 求解惑,double 与 float 的运算速度测试,为什么是这样?
: 重复执行4次一样的代码,只有第一次的时候,double与float有明显区别,后面三次区别就很小了
:
: ...................
--来自微水木3.5.11
--
FROM 140.206.195.*