C++ log 函数使用浮点精度
c++ log function is using floating point precision
当我给它一个非常接近 1.0 的数字时,我在以下函数中遇到了一个有趣的 seg 错误。特别是当数字在浮点精度下四舍五入为 1.0 时。
double get_random_element(double random_number)
{
if (random_number <= 0.0 || random_number >= 1.0)
throw std::runtime_error("Can't have a random number not on the range (0.0, 1.0)");
return -log(-log(random_number));
}
如果random_number为 1.0,则 log(1.0) = 0.0,零对数是一个未定义的计算,导致 seg 错误。但是,我本以为第一行的错误检查会阻止这种情况发生。Ddebuging显示,非常接近1的数字将通过错误检查,但无论如何都会从log函数返回0,这让我相信log函数只使用单个浮点精度。
我的包含如下,所以我只能假设我正在使用 math.h 的日志
#include <string>
#include <math.h>
#include <sstream>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#include <utility>
更新:正如所指出的,一个简单的解决方案是只使用浮点数作为参数,如果传入等于 1.0f 的数字以删除 std::numeric_limits::epsilon() 以给出一个可以安全地传递到双对数中的数字。
但我想回答的问题是,为什么调用接近但不等于 1 的数字的双对数会失败。
更新2:在测试项目中重新创建此问题后,我认为问题实际上出在输入中。如果我通过
double val = 1.0 - std::numerical_limits<double>::epsilon();
我对该功能没有问题。然而,我实际传入的是
boost::mt19937 random_generator;
double val = (random_generator()+1)/4294967297.0;
其中random_generator旨在返回范围 [0, 2^32 - 1] == [0,4294967295] 上的数字。所以我决定打入尽可能大的回报值
double val = (4294967295+1)/4294967297.0;
这很快给了我一个关于无符号 int 溢出的警告,果然生成了一个零。我正在重新编译以下内容:
get_random_element((random_generator()+1.0)/4294967297.0);
希望这种奇怪的行为能够得到解决。
更新3:我终于找到了这里发生的事情...像往常一样,它归结为用户错误(我自己是错误)。还有第二个控制路径通向此方法,该路径暂时将双精度值存储为浮点数,然后将其转换回双精度值,导致 0.9999999999 四舍五入为 1.0,然后传递到 -log(-log(x)) 函数并导致它倒下。我仍然不明白的是为什么我的检查
if (random_number <= 0.0 || random_number >= 1.0) throw runtime_error(blah)
在将错误输入传递到日志函数之前没有捕获错误输入?
我认为quamrana有一个很好的观点(它也立即引起了我的注意)。但是,我已经能够运行此代码片段相当长的时间:
#include <math.h>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real.hpp>
double get_random_element(double random_number)
{
if (random_number <= 0 || random_number >= 1.0f)
throw std::runtime_error("Can't have a random number not on the range (0.0, 1.0)");
return -::log(-::log(random_number));
}
int main()
{
boost::mt19937 rng;
boost::uniform_real<> random(std::numeric_limits<double>::epsilon(),1);
for (;;)
{
double r = random(rng);
double gre = get_random_element(r);
std::cout << "r = " << r << ", gre = " << gre << std::endl;
}
return 0; // not reached
}
例如:
sehe@meerkat:/tmp$ ./t | grep '^r = 0.999999'
r = 0.999999, gre = 14.4777
r = 0.999999, gre = 13.7012
r = 0.999999, gre = 14.0492
r = 0.999999, gre = 14.1161
[.... many many lines snipped ....]
r = 0.999999, gre = 14.3691
r = 0.999999, gre = 13.424
r = 0.999999, gre = 14.4822
r = 0.999999, gre = 14.286
r = 0.999999, gre = 14.4344
r = 0.999999, gre = 14.0572
r = 0.999999, gre = 14.0607
r = 0.999999, gre = 14.1126
r = 0.999999, gre = 13.575
r = 0.999999, gre = 13.4754
r = 0.999999, gre = 13.5486
r = 0.999999, gre = 14.1983
^C
real 18m14.005s
user 20m5.667s
sys 12m19.302s
也许你可以在静脉中使用类似的东西?
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 如何用数字处理log(0)
- 正在将csv文件读取为双精度矢量
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 如何在C++中的同一函数中使用字符串和双精度
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 如何计算具有指定类型的表达式的相对精度和绝对精度
- 安装opencv失败-粘贴CMakeError.log的内容
- 如何打印boost多精度128位无符号整数
- 检查是否以特定精度给出双精度
- 转换函数,将 std::数组的双精度作为参数或双精度作为参数单独转换
- C 字符串返回字符串的整数/双精度/长整型值
- 为什么将双精度转换为 int 似乎在第 16 位数字之后将其四舍五入?
- 如何使双精度值的 C++ 和 C# 中的结果相同
- Math.log是以一种避免log(1 x)的精度的方式实现的
- 双向量数组的log精度误差
- C++ log 函数使用浮点精度