我在C++编写一个程序来找到所有的解决方案一b = c ^,其中一个,b和c ^一起使用所有的数字0-9只出现一次.该方案在循环值一和b,并且在每次跑了数字计数程序一,b和一个b以检查是否数字的条件感到满意.
然而,当可以产生伪解一个b溢出整数限制.我最终使用以下代码检查:
unsigned long b, c, c_test;
...
c_test=c*b; // Possible overflow
if (c_test/b != c) {/* There has been an overflow*/}
else c=c_test; // No overflow
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来测试溢出?我知道有些芯片有一个内部标志,当溢出发生时会设置,但我从未见过通过C或C++访问它.
请注意,在C和C++中,签名 int溢出是未定义的行为,因此您必须在不实际导致它的情况下检测它.有关添加前的signed int overflow,请参阅在C/C++中检测带符号的溢出
Java如何处理整数下溢和溢出?
在此之后,您将如何检查/测试这是否正在发生?
无符号整数溢出由C和C++标准很好地定义.例如,C99标准(§6.2.5/9)声明
涉及无符号操作数的计算永远不会过度流动,因为无法用结果无符号整数类型表示的结果将以比结果类型可以表示的最大值大1的数量为模.
但是,这两个标准都声明有符号整数溢出是未定义的行为.再次,从C99标准(§3.4.3/1)
未定义行为的一个示例是整数流上的行为
这种差异是否存在历史或(甚至更好!)技术原因?
我想得到的总和1 + 2 + ... + 1000000000,但我在PHP和Node.js得到了有趣的结果.
PHP
$sum = 0;
for($i = 0; $i <= 1000000000 ; $i++) {
$sum += $i;
}
printf("%s", number_format($sum, 0, "", "")); // 500000000067108992
Run Code Online (Sandbox Code Playgroud)
Node.js的
var sum = 0;
for (i = 0; i <= 1000000000; i++) {
sum += i ;
}
console.log(sum); // 500000000067109000
Run Code Online (Sandbox Code Playgroud)
可以使用计算正确的答案
1 + 2 + ... + n = n(n+1)/2
Run Code Online (Sandbox Code Playgroud)
正确答案= 500000000500000000,所以我决定尝试另一种语言.
走
var sum , i int64
for i = 0 …Run Code Online (Sandbox Code Playgroud) long long int n = 2000*2000*2000*2000; // overflow
long long int n = pow(2000,4); // works
long long int n = 16000000000000; // works
Run Code Online (Sandbox Code Playgroud)
为什么第一个溢出(乘以整数文字常量以分配给 long long)?
它与第二个或第三个有什么不同?
以下代码块将输出设为0.
public class HelloWorld{
public static void main(String []args){
int product = 1;
for (int i = 10; i <= 99; i++) {
product *= i;
}
System.out.println(product);
}
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么会这样吗?
添加两个32位整数会导致整数溢出:
uint64_t u64_z = u32_x + u32_y;
Run Code Online (Sandbox Code Playgroud)
如果首先将32位整数中的一个整流或添加到64位整数,则可以避免此溢出.
uint64_t u64_z = u32_x + u64_a + u32_y;
Run Code Online (Sandbox Code Playgroud)
但是,如果编译器决定重新排序添加:
uint64_t u64_z = u32_x + u32_y + u64_a;
Run Code Online (Sandbox Code Playgroud)
整数溢出可能仍会发生.
是否允许编译器进行这样的重新排序,或者我们是否可以相信它们会注意到结果不一致并保持表达顺序不变?
这是一个例子来说明我的问题,其中涉及一些我不能在这里发布的更复杂的代码.
#include <stdio.h>
int main()
{
int a = 0;
for (int i = 0; i < 3; i++)
{
printf("Hello\n");
a = a + 1000000000;
}
}
Run Code Online (Sandbox Code Playgroud)
这个程序在我的平台上包含未定义的行为,因为它a会在第3个循环中溢出.
这是否会使整个程序具有未定义的行为,或者仅在溢出实际发生之后?编译器是否可能a 会解决溢出问题,因此它可以声明整个循环未定义,并且不会打扰运行printfs,即使它们都在溢出之前发生?
(标记为C和C++,即使它们不同,因为如果它们不同,我会对这两种语言的答案感兴趣.)
我想定义一个带有unsigned intas参数的函数,并向参数返回一个int全等模UINT_MAX + 1.
第一次尝试可能如下所示:
int unsigned_to_signed(unsigned n)
{
return static_cast<int>(n);
}
Run Code Online (Sandbox Code Playgroud)
但正如任何语言律师所知,从无符号转换为大于INT_MAX的已签名值是实现定义的.
我想实现这一点,以便(a)它只依赖于规范规定的行为; (b)它在任何现代机器上编译成无操作并优化编译器.
对于奇怪的机器......如果没有签名的int congruent将UINT_MAX + 1模数为unsigned int,那么假设我想抛出一个异常.如果有多个(我不确定这是否可能),那么就说我想要最大的一个.
好的,第二次尝试:
int unsigned_to_signed(unsigned n)
{
int int_n = static_cast<int>(n);
if (n == static_cast<unsigned>(int_n))
return int_n;
// else do something long and complicated
}
Run Code Online (Sandbox Code Playgroud)
当我不是一个典型的二元补充系统时,我并不太关心效率,因为我认为不太可能.如果我的代码成为2050年无所不在的符号量级系统的瓶颈,那么,我敢打赌,有人可以解决这个问题并对其进行优化.
现在,第二次尝试非常接近我想要的.尽管转换int为某些输入的实现定义,但是unsigned标准保证转换为保留模UINT_MAX + 1的值.所以条件确实检查我想要什么,它将在我可能遇到的任何系统上编译成什么.
但是......我仍然在int没有首先检查它是否会调用实现定义的行为.在2050年的一些假设系统中,它可以做谁知道什么.所以我想说我想避免这种情况.
问题:我的"第三次尝试"应该是什么样的?
回顾一下,我想:
[更新]
让我举一个例子来说明为什么这不是一个微不足道的问题.
考虑具有以下属性的假设C++实现:
sizeof(int) 等于4sizeof(unsigned) 等于4INT_MAX 等于32767INT_MIN等于-2 …我遇到了下面的C++程序(源代码):
#include <iostream>
int main()
{
for (int i = 0; i < 300; i++)
std::cout << i << " " << i * 12345678 << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它看起来像一个简单的程序,并在我的本地机器上提供正确的输出,例如:
0 0
1 12345678
2 24691356
...
297 -628300930
298 -615955252
299 -603609574
Run Code Online (Sandbox Code Playgroud)
但是,在像codechef这样的在线IDE上,它提供了以下输出:
0 0
1 12345678
2 24691356
...
4167 -95167326
4168 -82821648
4169 -7047597
Run Code Online (Sandbox Code Playgroud)
为什么for循环不在300处终止?此程序也始终终止4169.为什么4169而不是其他一些价值?