The*_*ist 4 c++ optimization fixed-point integer-overflow c++11
我有一些针对某些财务应用程序的定点实现.它基本上是一个包含在类中的整数,它基于给定N的十进制数作为小数.该类是偏执的并检查溢出,但是当我在发布模式下运行我的测试时,它们都失败了,最后我创建了这个演示问题的最小例子:
#include <iostream>
#include <sstream>
template <typename T, typename U>
typename std::enable_if<std::is_convertible<U, std::string>::value, T>::type
FromString(U&& str)
{
std::stringstream ss;
ss << str;
T ret;
ss >> ret;
return ret;
}
int main()
{
int NewAccu=32;
int N=10;
using T = int64_t;
T l = 10;
T r = FromString<T>("1" + std::string(NewAccu - N, '0'));
if (l == 0 || r == 0) {
return 0;
}
T res = l * r;
std::cout << l << std::endl;
std::cout << r << std::endl;
std::cout << res << std::endl;
std::cout << (res / l) << std::endl;
std::cout << std::endl;
if ((res / l) != r) {
throw std::runtime_error(
"FixedPoint Multiplication Overflow while upscaling [:" + std::to_string(l) + ", " + std::to_string(r) + "]");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Clang 6会发生这种情况,我的版本是:
$ clang++ --version
clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Run Code Online (Sandbox Code Playgroud)
这很有趣,因为它是一个令人印象深刻的优化,但这破坏了我的应用程序,并防止我检测溢出.我能够在这里用g ++重现这个问题.它不会在那里抛出异常.
请注意,在调试模式下抛出异常,但它不在释放模式下.
正如@Basile所说,有符号整数溢出是一种未定义的行为,因此编译器可以以任何方式处理它 - 甚至优化它以获得性能优势.因此在发生整数溢出后检测它是否为时已晚.相反,您应该在它发生之前预测整数溢出.
这是我对整数乘法的溢出预测的实现:
#include <limits>
template <typename T>
bool predict_mul_overflow(T x, T y)
{
static_assert(std::numeric_limits<T>::is_integer, "predict_mul_overflow expects integral types");
if constexpr (std::numeric_limits<T>::is_bounded)
{
return ((x != T{0}) && ((std::numeric_limits<T>::max() / x) < y));
}
else
{
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
true如果x * y预测整数乘法溢出,则函数返回.
请注意,虽然unsigned溢出在模运算方面是明确定义的,但signed溢出是一种未定义的行为.然而,所呈现的功能也适用于signed并且也是unsigned T类型.
| 归档时间: |
|
| 查看次数: |
498 次 |
| 最近记录: |