2015-10-24 24 views
0

如果我理解documentationcorrectly,我们应该能够使用ldexp恢复分解为尾数签署和frexp指数浮点数。我一直无法做到这一点。请看下面的代码:反相frexp与ldexp

#include <cmath> 
#include <iostream> 
#include <limits> 

template <typename T> 
void float_info() { 
    std::cout << "max=" << std::numeric_limits<T>::max()   << 
     ", max_exp=" << std::numeric_limits<T>::max_exponent << 
     ", max_10_exp=" << std::numeric_limits<T>::max_exponent10 << 
     ", min="  << std::numeric_limits<T>::min()   << 
     ", min_exp=" << std::numeric_limits<T>::min_exponent << 
     ", min_10_exp=" << std::numeric_limits<T>::min_exponent10 << 
     ", dig="  << std::numeric_limits<T>::digits10  << 
     ", mant_dig=" << std::numeric_limits<T>::digits   << 
     ", epsilon=" << std::numeric_limits<T>::epsilon()  << 
     ", radix="  << std::numeric_limits<T>::radix   << 
     ", rounds="  << std::numeric_limits<T>::round_style << std::endl; 
} 

template <typename T> 
void compare(T a, T b) { 
    std::cout << a << " " << b << " (" << 
     (a != b ? "un" : "") << "equal)" << std::endl; 
} 

template<typename T> 
void test_ldexp() { 
    float_info<T>(); 

    T x = 1 + std::numeric_limits<T>::epsilon(); 
    T y = ldexp(x, 0); 
    int exponent; 
    T mantissa = frexp(x, &exponent); 
    T z = ldexp(mantissa, exponent); 

    compare(x, y); 
    compare(x, z); 

    std::cout << std::endl; 
} 

int main() { 
    std::cout.precision(25); 
    test_ldexp<float>(); 
    test_ldexp<double>(); 
    test_ldexp<long double>(); 
} 

g++在Ubuntu 14.04.3 LTS(4.8.4版本)编译,输出为:

max=3.402823466385288598117042e+38, max_exp=128, max_10_exp=38, 
min=1.175494350822287507968737e-38, min_exp=-125, min_10_exp=-37, dig=6, 
mant_dig=24, epsilon=1.1920928955078125e-07, radix=2, rounds=1 
1.00000011920928955078125 1.00000011920928955078125 (equal) 
1.00000011920928955078125 1.00000011920928955078125 (equal) 

max=1.797693134862315708145274e+308, max_exp=1024, max_10_exp=308, 
min=2.225073858507201383090233e-308, min_exp=-1021, min_10_exp=-307, dig=15, 
mant_dig=53, epsilon=2.220446049250313080847263e-16, radix=2, rounds=1 
1.000000000000000222044605 1.000000000000000222044605 (equal) 
1.000000000000000222044605 1.000000000000000222044605 (equal) 

max=1.189731495357231765021264e+4932, max_exp=16384, max_10_exp=4932, 
min=3.362103143112093506262678e-4932, min_exp=-16381, min_10_exp=-4931, dig=18, 
mant_dig=64, epsilon=1.084202172485504434007453e-19, radix=2, rounds=1 
1.00000000000000000010842 1 (unequal) 
1.00000000000000000010842 1 (unequal) 

当使用long double小号我们似乎正在失去的东西通过分解我们的xfrexpr。如果我使用python3(版本3.4.3)运行以下脚本,我可以实现我期望的行为。

import math 
import sys 

def compare(a, b): 
    print('{a} {b} ({pre}equal)'.format(a=a, b=b, 
     pre='un' if a != b else '')) 

x = 1 + sys.float_info.epsilon 
mantissa, exponent = math.frexp(x) 

print(sys.float_info) 
compare(x, math.ldexp(x, 0)) 
compare(x, math.ldexp(mantissa, exponent)) 

输出是:

sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, 
min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, 
mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1) 
1.0000000000000002 1.0000000000000002 (equal) 
1.0000000000000002 1.0000000000000002 (equal) 

请注意,这只是使用double秒。

我试图读取cmath头文件,了解如何实现frexprldexpr,但我无法理解它。到底是怎么回事?

回答

1

修改您的C++程序,方法是在test_ldexp函数中调用compare之前包含typeinfo标题并插入以下行。现在

std::cout << "types:" << std::endl; 
std::cout << " x   : " << typeid(x).name() << std::endl; 
std::cout << " mantissa : " << typeid(frexp(x, &exponent)).name() 
      << std::endl; 
std::cout << " ldexp(...): " << typeid(ldexp(x, 0)).name() << std::endl; 
std::cout << " ldexp(...): " << typeid(ldexp(mantissa, exponent)).name() 
      << std::endl; 

输出是:

max=3.402823466385288598117042e+38, max_exp=128, max_10_exp=38, 
min=1.175494350822287507968737e-38, min_exp=-125, min_10_exp=-37, dig=6, 
mant_dig=24, epsilon=1.1920928955078125e-07, radix=2, rounds=1 
types: 
    x   : f 
    mantissa : d 
    ldexp(...): d 
    ldexp(...): d 
1.00000011920928955078125 1.00000011920928955078125 (equal) 
1.00000011920928955078125 1.00000011920928955078125 (equal) 

max=1.797693134862315708145274e+308, max_exp=1024, max_10_exp=308, 
min=2.225073858507201383090233e-308, min_exp=-1021, min_10_exp=-307, dig=15, 
mant_dig=53, epsilon=2.220446049250313080847263e-16, radix=2, rounds=1 
types: 
    x   : d 
    mantissa : d 
    ldexp(...): d 
    ldexp(...): d 
1.000000000000000222044605 1.000000000000000222044605 (equal) 
1.000000000000000222044605 1.000000000000000222044605 (equal) 

max=1.189731495357231765021264e+4932, max_exp=16384, max_10_exp=4932, 
min=3.362103143112093506262678e-4932, min_exp=-16381, min_10_exp=-4931, dig=18, 
mant_dig=64, epsilon=1.084202172485504434007453e-19, radix=2, rounds=1 
types: 
    x   : e 
    mantissa : d 
    ldexp(...): d 
    ldexp(...): d 
1.00000000000000000010842 1 (unequal) 
1.00000000000000000010842 1 (unequal) 

frexprldexpr正在返回double没什么不管你放什么类型!看起来您正在使用math.h中定义的功能(请参阅herehere),而不是cmath中定义的功能。将您的电话替换为frexprldexpr,并拨打std::frexprstd::ldexpr,您的代码将按预期工作。