我正在 Arduino 上编写一些代码,该代码需要快速运行并对整数百分比进行粗略近似。
例如,给定一个数字,我想找到它的 90%、70% 或 30% 等。最明显的方法是乘以浮点,例如。x * 0.9;或 x * 0.3;但因为我需要速度,所以我想避免浮点计算。如果我只是除以 2 的幂,我会进行按位移位,但是是否有类似的技术可以使用整数来近似 90%、80% 等?
performance heuristics arduino integer-division integer-arithmetic
在执行带有溢出检查的整数算术时,计算通常需要组合多个算术运算。在 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 架构上优化上述任一模式的经验,以判断显式展开是否值得,尤其是对于更复杂的表达式?
我的问题仅限于 256 位无符号整数。
我有一个值x,我需要按比率对其进行除垢n / d,其中n < d。
简单的解决方案当然是x * n / d,但问题是x * n可能会溢出。
我正在寻找任何可能有助于获得尽可能准确的结果的算术技巧。
在计算之前将每个 和 除以n并d不能保证成功。gcd(n, d)x * n / d
我可以使用任何流程(迭代或其他)来解决这个问题吗?
请注意,我愿意选择不准确的解决方案,但我需要能够估计错误。
有一个相对知名的技巧可以取消设置最右边的一个位:
y = x & (x - 1) // 0b001011100 & 0b001011011 = 0b001011000 :)
Run Code Online (Sandbox Code Playgroud)
我发现自己有一个紧密的循环来清除最右边的 n 位,但是有更简单的代数技巧吗?
假设 n 相对较大(对于 64 位整数,n 必须小于 64,但通常约为 20-30)。
// x = 0b001011100 n=2
for (auto i=0; i<n; i++) x &= x - 1;
// x = 0b001010000
Run Code Online (Sandbox Code Playgroud)
我翻阅了 TAOCP Vol4 几次,但找不到任何灵感。
也许有一些硬件支持?
我想知道 x**2 还是 x*x 更快
def sqr(x):
for i in range (20):
x = x**2
return x
def sqr_(x):
for i in range (20):
x = x*x
return x
Run Code Online (Sandbox Code Playgroud)
当我计时时,这就是我得到的:
The time it takes for x**2: 101230500
The time it takes for x*x: 201469200
Run Code Online (Sandbox Code Playgroud)
我已经尝试了很多很多次,它们要么相等,要么 x ** 2 比 x * x 快。但 x*x 永远不会比 x**2 快。
所以我反驳了代码:
对于 x**2:
5 12 LOAD_FAST 0 (x)
14 LOAD_CONST 2 (2)
16 BINARY_POWER
18 STORE_FAST 0 (x)
20 JUMP_ABSOLUTE 8
Run Code Online (Sandbox Code Playgroud)
对于 x*x: …
以下程序:
#include <iostream>
#include <string>
int main ()
{
unsigned char result1 {0};
unsigned char result2 {0};
result1 = (result1 - 1) % 8;
result2 = result2 - 1;
result2 = result2 % 8;
std::cout << "result1 is " << std::to_string (result1) << '\n';
std::cout << "result2 is " << std::to_string (result2) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
产生以下输出:
result1 is 255
result2 is 7
Run Code Online (Sandbox Code Playgroud)
为什么result1和result2的计算结果不同?
我尝试了几个编译器,但它们都产生相同的结果,所以这一定是我不明白的地方。
在C中,如果我想将int除以2,则x%2应该运行得快,(x%10)% 2
因为好的编译器只会查看最后一位.但是在具有无限精度算术的语言中呢?
特别是在Haskell中会更快(或者它们是相同的速度):even x或者even (quot x 10)?
compiler-construction haskell haskell-platform integer-arithmetic
假设我有Long someLong = 1004L.我可以使用什么有效的方法将其舍入到1000L?请注意,我实际上并不知道,someLong == 1004L所以我不能简单地这样做someLong -= 4L;.我需要一个可推广的方法.我也希望能够向下舍入到每个5而不是每个10,例如一个1005L舍入到的函数(因为如果我们舍入为5s然后它将向上舍入而不是向下舍入).
更多的例子..可能是我有1926L,我想要圆润到5我需要的意思1925L.或者我需要四舍五入到10我需要的意义1930L.
C语言有签名和无符号类型,如char和int.我不确定,它是如何在汇编级别实现的,例如在我看来,有符号和无符号的乘法会带来不同的结果,因此汇编执行无符号和有符号算术或仅执行一次,这在某种程度上是模拟的不同的情况?
我知道可以通过进位标志增加两个大于给定处理器总线大小的无符号整数.通常,对于使用溢出标志的有符号整数也是如此.但是,Intel 8085只拥有一个Sign标志,而不是一个Overflow标志,那么它如何处理有符号整数运算呢?