我正在尝试在Linux(x86)上学习GCC内联汇编,我的第一个实验是尝试实现乘法的整数溢出检测.这似乎很容易,但它有副作用,我不明白.
所以,在这里我想要将两个无符号8位整数相乘,并查看结果是否溢出.基本上我只是将第一个操作数加载到AL寄存器中,将另一个操作数加载到BL寄存器中,然后使用该mul指令.结果存储为AX寄存器中的16位值.所以我然后将AX寄存器中的值复制到我的C变量b,除非它溢出.如果它溢出我设置c为1.
uint8_t a = 10;
uint8_t b = 25;
uint8_t c = 0; // carry flag
__asm__
(
"clc;" // Clear carry flag
"movb %3, %%al;" // Load b into %al
"movb %2, %%bl;" // Load a into %bl
"mul %%bl;" // Multiply a * b (result is stored in %ax)
"movw %%ax, %0;" // Load result into b
"jnc out;" // Jump to 'out' if the carry flag is not set
"movb …Run Code Online (Sandbox Code Playgroud) 由于一个聪明而复杂的原因,我不想解释(因为它涉及以非常丑陋和hacky的方式制作计时器),我写了一些类似的C#代码:
int i = 0;
while (i >= 0) i++; //Should increment forever
Console.Write(i);
Run Code Online (Sandbox Code Playgroud)
我希望程序永远挂起或崩溃或者其他东西,但是,令我惊讶的是,在等待大约20秒左右之后,我得到了这个输出:
-2147483648
Run Code Online (Sandbox Code Playgroud)
编程已经教会了很多东西,但我仍然无法理解为什么不断增加一个数字导致它最终变成负面...这里发生了什么?
我正在尝试解决一个关于 SPOJ 的问题,它需要模幂运算。我正在使用以下 C 代码
long long modpow(long long a,long long b,long long mod)
{
long long product,pseq;
product=1
pseq=a%mod;
while(b>0)
{
if(b&1)
product=(product*pseq)%mod;
pseq=(pseq*pseq)%mod;
b>>=1
}
return product;
}
Run Code Online (Sandbox Code Playgroud)
问题是当我想计算时(2^249999999997)%999999999989,它会0因为溢出而给出答案。如何避免溢出?
有没有办法捕获整数异常,gfortran或者ifort像捕获浮点异常一样?
考虑这个简单的程序来计算阶乘:
program factorial
use, intrinsic :: iso_fortran_env
implicit none
integer(8) :: fac
real(REAL64) :: facR
integer,parameter :: maxOrder = 30
integer :: i
fac = 1 ; facR = 1.e0_REAL64
do i=2,maxOrder
fac=fac*i ; facR=facR*real(i,REAL64)
write(*,*) i, fac, facR
enddo ! i
end program
Run Code Online (Sandbox Code Playgroud)
在某些时候会出现溢出 -integer(8)如此处所示,它将发生在 21 左右。但是如果没有使用浮点数作为参考的计算,我无法确定......
我正在开发一个 python 程序来计算斐波那契数列中的数字。这是我的代码:
import math
def F(n):
return ((1+math.sqrt(5))**n-(1-math.sqrt(5))**n)/(2**n*math.sqrt(5))
def fib(n):
for i in range(n):
print F(i)
Run Code Online (Sandbox Code Playgroud)
我的代码使用这个公式来查找斐波那契数列中的第 N 个数字:

这可以计算斐波那契数列中的许多数字,但我确实遇到了溢出错误。
如何改进此代码并防止溢出错误?
注意:我使用的是 python 2.7。
CBMC在以下行中检测到可能的无符号加法溢出:
l = (t + *b)&(0xffffffffL);
c += (l < t);
Run Code Online (Sandbox Code Playgroud)
我同意第一行有可能出现溢出,但我正在处理CBMC无法查看的下一行的进位.如果有溢出,我设置进位1.所以,因为我知道这个,这就是我希望我的代码工作的方式,我想继续进行验证过程.那么,我怎么告诉CBMC忽略这个错误并继续前进呢?
在执行带有溢出检查的整数算术时,计算通常需要组合多个算术运算。在 Rust 中链接检查算术的一种直接方法是使用checked_*方法和Option链接:
fn calculate_size(elem_size: usize,
length: usize,
offset: usize)
-> Option<usize> {
elem_size.checked_mul(length)
.and_then(|acc| acc.checked_add(offset))
}
Run Code Online (Sandbox Code Playgroud)
但是,这告诉编译器为每个基本操作生成一个分支。我遇到了一种使用overflowing_*方法更展开的方法:
fn calculate_size(elem_size: usize,
length: usize,
offset: usize)
-> Option<usize> {
let (acc, oflo1) = elem_size.overflowing_mul(length);
let (acc, oflo2) = acc.overflowing_add(offset);
if oflo1 | oflo2 {
None
} else {
Some(acc)
}
}
Run Code Online (Sandbox Code Playgroud)
不考虑溢出而继续计算并使用按位 OR 聚合溢出标志可确保在整个评估中最多执行一个分支(前提是overflowing_*生成无分支代码的实现)。这种优化友好的方法更麻烦,并且在处理中间值时需要谨慎。
有没有人有过 Rust 编译器如何在各种 CPU 架构上优化上述任一模式的经验,以判断显式展开是否值得,尤其是对于更复杂的表达式?
我正在阅读有关未定义行为的内容,我不确定它是否只是一个编译时功能,或者它是否可以在执行时发生.
我很好理解这个例子(这是从维基百科的未定义行为页面中提取的):
C语言的一个例子:
Run Code Online (Sandbox Code Playgroud)int foo(unsigned x) { int value = 5; value += x; if (value < 5) bar(); return value; }值
x不能为负,并且由于有符号整数溢出是C中未定义的行为,编译器可以假设在if检查行value >= 5.因此编译器可以忽略if和调用该函数bar,因为if它没有副作用,并且它的条件永远不会被满足.因此,上面的代码在语义上等同于:Run Code Online (Sandbox Code Playgroud)int foo(unsigned x) { int value = 5; value += x; return value; }
但这发生在编译时.
如果我写,例如:
void foo(int x) {
if (x + 150 < 5)
bar();
}
int main() {
int x;
std::cin >> x;
foo(x);
}
Run Code Online (Sandbox Code Playgroud)
然后用户键入 …
我正在尝试为Rust u32和u64数据类型实现快速素性测试.作为它的一部分,我需要计算(n*n)%d其中n和d是u32(或u64,分别地).
虽然结果很容易适合数据类型,但我对如何计算它感到茫然.据我所知,没有处理器原语.
因为u32我们可以伪造它 - 铸造u64,以便产品不会溢出,然后取模数,然后再回落u32,知道这不会溢出.但是因为我没有u128数据类型(据我所知),这个技巧不起作用u64.
因此,对u64,我能想到的最明显的方式来完成,这是莫名其妙地计算x*y得到一对(carry, product)的u64,所以我们捕获,而不是仅仅失去它(或恐慌,或其他)溢出量.
有没有办法做到这一点?还是另一种解决问题的标准方法?
我正在向女儿展示R中两个111..111数乘法的魔术模式,例如
> options(scipen=999)
> 1^2
[1] 1
> 11^2
[1] 121
> 111^2
[1] 12321
> 1111^2
[1] 1234321
> 11111^2
[1] 123454321
> 111111^2
[1] 12345654321
> 1111111^2
[1] 1234567654321
> 11111111^2
[1] 123456787654321
> 111111111^2
[1] 12345678987654320
Run Code Online (Sandbox Code Playgroud)
一切正常,直到达到9位数。从最后一行可以看出,答案显然是错误的。它应该是1234567898765432 * 1 *,而不是1234567898765432 * 0 *。
我在Macbook Pro笔记本电脑上的R(v3.6.1,x86_64-apple-darwin15.6.0,64位)中运行此文件。
有人说这可能是整数溢出引起的。这里有两个问题:
谁能解释这是怎么发生的?例如,最后一个1如何变为0?
如何在R中获得正确答案?
谢谢。