提问者:小点点

C浮点类型不使用科学符号来表示非常小的值?


我正在写一个算法,处理Logit-正态分布变换,它的特点是,有足够高的sigmas/means,值可以非常紧密地“压缩”到0和1的边缘。我遇到了应该不同的值碰撞的问题,因为C双精度不能代表足够的数字。例如,我将sigmoid/logistic函数应用于两个足够高但不同的值,如果双精度可以保持更高的精度,结果是相同的。

我可以通过聚合碰撞到相同值上的样本来解决这个问题。但问题是,在1左右,碰撞发生了,因为数字是这样表示的:例如:0。999999999953。但在0附近,它没有发生,因为C开始用科学记数法表示值,像这样:0.12949384e-300。后者可以实现更高的精度,因此这里不会发生碰撞。但我需要对0和1周围的值进行对称行为,以确保两边的计算结果相同。

C中是否有这样的类型在表示极小的值时不会自动切换到科学符号?所以我可以在0附近实现与1附近相同的行为?


共1个答案

匿名用户

您可以使用类型long double。它通常具有x86 80位精度,这是8087协处理器的原始精度。

请注意,Microsoft很久以前就放弃了对它的支持。

GCC支持实现IEEE754四重精度的类型__float128。这很好,因为如果您使用Linux它可能已经存在。

Boost多精度为上述提供了128位跨平台外观。但是,您通常会将boost库依赖项带入您的应用程序,这在某些情况下可能令人望而生畏。更新:boost多精度的float128无法在MSVC/Windows上编译。

示例:

#include <iostream>
#include <limits>
#include <cmath>
#include "boost/format.hpp"
#include <boost/multiprecision/float128.hpp>

namespace mp = boost::multiprecision;

template< typename T >
[[gnu::noinline]] T calc(T a,T b,T c) {
    return T(1) - (T(1)/a + T(1)/b + T(1)/c );
}

int main() {
    std::cout << "     Epsilon        Error"<< std::endl;
    boost::format fmt( "%12.6g %12.6g" );
    std::cout << fmt % std::numeric_limits<double>::epsilon() % calc<double>(3,2,6) << std::endl;
    std::cout << fmt % std::numeric_limits<long double>::epsilon() % calc<long double>(3,2,6) << std::endl;
    std::cout << fmt % double(std::numeric_limits<__float128>::epsilon()) % double(calc<__float128>(3,2,6)) << std::endl;
    std::cout << fmt % std::numeric_limits<mp::float128>::epsilon() % calc<mp::float128>(3,2,6) << std::endl;
}

结果在

Program stdout
     Epsilon        Error
 2.22045e-16  1.11022e-16
  1.0842e-19            0
           0  9.62965e-35
 1.92593e-34  9.62965e-35

编译器资源管理器链接

但是请注意,128位精度会带来巨大的性能损失。我使用上述公式编写了一个基准测试,结果是:

-------------------------------------------------------------
Benchmark                   Time             CPU   Iterations
-------------------------------------------------------------
Calc<double>           375575 ns       375514 ns         1864
Calc<long double>      531313 ns       531228 ns         1318
Calc<__float128>     12943995 ns     12941473 ns           54
Calc<mp::float128>   13074108 ns     13071816 ns           54

相关问题