C++ 数学在 65536 之后很奇怪
C++ Math Weird After 65536
这是我问的第一个问题,所以我不确定该说什么。基本上,我编写了一个程序来查找矩形棱柱的对角线,其中长度、宽度和高度的输入是 1 - 100,000 之间的整数。 (如果它是一个整数,这个函数的输出只会在控制台中说明。)一切似乎都有效,直到它到达数字 65536,之后,下一个输出是 0。
编程新手,如有遗漏,欢迎追问,先谢谢大家了!
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include<math.h>
#include <cmath>
int l = 1;
int w = 1;
int h = 1;
double temp1;
double temp2;
double Hypo1;
double temp3;
double Hypo2;
double temp4;
int main(){
while(h < 100000){
//Math to find diagonal of rectangular prism.
temp1 = l * l;
temp2 = w * w;
Hypo1 = temp1 + temp2;
temp3 = h * h;
temp4 = Hypo1 + temp3;
Hypo2 = sqrt(temp4);
//Output if answer is a whole number.
if(abs(floor(Hypo2)) == Hypo2){
std::cout << "<Length = "; std::cout << l;
std::cout << " | Width = "; std::cout << w;
std::cout << " | Height = "; std::cout << h;
std::cout << ">";
std::cout << " Total:"; std::cout << Hypo2 << std::endl;
}
//Add one to each input.
if(l == w && l == h){
l++;
}
else if(w < l && w == h){
w++;
}
else if(h < l && h < w){
h++;
}
}
}
您将 h
声明为 int
,因此 h*h
的结果也将是一个整数。在计算完成后转换为 double。
如果您查看 INT_MAX
,您的平台上可能 2,147,483,647
。
因此,如果您查看 65536 * 65536
,它是 4,294,967,296
,远远超出了值范围。
如果先把其中一个因子转换成double值,运气可能会好一些temp3 = double(h) * h
欢迎来到 Overflow 的奇迹。
所以,这是正在发生的事情:
您正在使用 int
,它将值存储在一个 4 字节(32 位)变量中。当您将存储在 X 位中的两个数字相乘时,您可能需要将结果存储在 2*X 位中。
在这种情况下,65536 在二进制中是 0000 0000 0000 0001 0000 0000 0000 0000(在十六进制中,0x 0001 0000 ).当您将 65536 自相乘时,结果将为 1 0000 0000 0000 0000 0000 0000 0000 0000(十六进制,0x 1 0000 0000)。现在,问题是这个值需要 33 位才能正确存储。因为它只有 32,所以它存储了 32 个最低有效位 并且 丢弃了最高有效位 。因此,存储的值将为 0。这也是更大值的情况。
要更正此问题,请将 int
替换为 long long
或者更好的是 unsigned long long
.
作为个人建议,习惯 uint32_t
和其他标准类型。他们会派上用场的。要使用这些,#include <cstdint>
。在这种情况下,您应该使用 uint64_t
将无符号整数存储在 64 位变量中
这是我问的第一个问题,所以我不确定该说什么。基本上,我编写了一个程序来查找矩形棱柱的对角线,其中长度、宽度和高度的输入是 1 - 100,000 之间的整数。 (如果它是一个整数,这个函数的输出只会在控制台中说明。)一切似乎都有效,直到它到达数字 65536,之后,下一个输出是 0。 编程新手,如有遗漏,欢迎追问,先谢谢大家了!
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include<math.h>
#include <cmath>
int l = 1;
int w = 1;
int h = 1;
double temp1;
double temp2;
double Hypo1;
double temp3;
double Hypo2;
double temp4;
int main(){
while(h < 100000){
//Math to find diagonal of rectangular prism.
temp1 = l * l;
temp2 = w * w;
Hypo1 = temp1 + temp2;
temp3 = h * h;
temp4 = Hypo1 + temp3;
Hypo2 = sqrt(temp4);
//Output if answer is a whole number.
if(abs(floor(Hypo2)) == Hypo2){
std::cout << "<Length = "; std::cout << l;
std::cout << " | Width = "; std::cout << w;
std::cout << " | Height = "; std::cout << h;
std::cout << ">";
std::cout << " Total:"; std::cout << Hypo2 << std::endl;
}
//Add one to each input.
if(l == w && l == h){
l++;
}
else if(w < l && w == h){
w++;
}
else if(h < l && h < w){
h++;
}
}
}
您将 h
声明为 int
,因此 h*h
的结果也将是一个整数。在计算完成后转换为 double。
如果您查看 INT_MAX
,您的平台上可能 2,147,483,647
。
因此,如果您查看 65536 * 65536
,它是 4,294,967,296
,远远超出了值范围。
如果先把其中一个因子转换成double值,运气可能会好一些temp3 = double(h) * h
欢迎来到 Overflow 的奇迹。
所以,这是正在发生的事情:
您正在使用 int
,它将值存储在一个 4 字节(32 位)变量中。当您将存储在 X 位中的两个数字相乘时,您可能需要将结果存储在 2*X 位中。
在这种情况下,65536 在二进制中是 0000 0000 0000 0001 0000 0000 0000 0000(在十六进制中,0x 0001 0000 ).当您将 65536 自相乘时,结果将为 1 0000 0000 0000 0000 0000 0000 0000 0000(十六进制,0x 1 0000 0000)。现在,问题是这个值需要 33 位才能正确存储。因为它只有 32,所以它存储了 32 个最低有效位 并且 丢弃了最高有效位 。因此,存储的值将为 0。这也是更大值的情况。
要更正此问题,请将 int
替换为 long long
或者更好的是 unsigned long long
.
作为个人建议,习惯 uint32_t
和其他标准类型。他们会派上用场的。要使用这些,#include <cstdint>
。在这种情况下,您应该使用 uint64_t
将无符号整数存储在 64 位变量中