Chinaunix首页 | 论坛 | 博客
  • 博客访问: 990940
  • 博文数量: 158
  • 博客积分: 4380
  • 博客等级: 上校
  • 技术积分: 2367
  • 用 户 组: 普通用户
  • 注册时间: 2006-09-21 10:45
文章分类

全部博文(158)

文章存档

2012年(158)

我的朋友

分类: C/C++

2012-11-20 09:47:44

// 以下代码在VC++6.0和G++3.4.2中编译通过
// 为了兼容VC++6.0,不得不放弃模板,且long double手工编码
// 如果你的CPU不是足够快速,或内存容量不大,请把long double的测试部分删除,千万别死撑


#include
#include
#include
#include
#include
#include
using namespace std;

// 实数类: 提供乘2,除2,加,和输出操作
class foo_
{
    friend ostream& operator<<( ostream& os, const foo_& f );
public:
    typedef char value_type;
    typedef vector container;
    typedef container::size_type size_type;
    foo_( double n = 0.0 )
    {
        if( n == 1.0 ) { integral.push_back( 1 ); }
        else if( n == 0.0 ) { }
        else if( n == 0.5 ) { fractional.push_back( 5 ); }
        else { assert( false ); }
    }
    void mul2( void )
    {
        unsigned int c = 0;
        for( size_type i=0; i        {
            unsigned int n = fractional[ fractional.size()-i-1 ] * 2 + c;
            c = n / 10;
            fractional[ fractional.size()-i-1 ] = n % 10;
        }
        while( !fractional.empty() && fractional.back() == 0 ) fractional.pop_back();
        for( size_type j=0; j        {
            unsigned int n = integral[j] * 2 + c;
            c = n / 10;
            integral[j] = n % 10;
        }
        if( c != 0 )
            integral.push_back( (char)c );
    }
    void div2( void )
    {
        unsigned int c = 0;
        for( size_type i=0; i        {
            unsigned int n = integral[ integral.size()-i-1 ] + c*10;
            integral[ integral.size()-i-1 ] = n / 2;
            c = n - integral[ integral.size()-i-1 ]*2;
        }
        while( !integral.empty() && integral.back() == 0 ) integral.pop_back();
        for( size_type j=0; j        {
            unsigned int n = fractional[j] + c*10;
            fractional[j] = n / 2;
            c = n - fractional[j]*2;
           
        }
        if( c != 0 )
            fractional.push_back( (value_type)5 );
    }
    void add( const foo_& f )
    {
        unsigned int c = 0;
        container rhs = f.fractional;
        size_type maxlen = rhs.size() > fractional.size() ? rhs.size() : fractional.size();
        rhs.resize( maxlen );
        fractional.resize( maxlen );
        for( size_type i=0; i        {
            unsigned int n = fractional[ fractional.size()-i-1 ] + rhs[ fractional.size()-i-1 ] + c;
            c = n / 10;
            fractional[ fractional.size()-i-1 ] = n % 10;
        }
        while( !fractional.empty() && fractional.back() == 0 ) fractional.pop_back();
        rhs = f.integral;
        maxlen = rhs.size() > integral.size() ? rhs.size() : integral.size();
        rhs.resize( maxlen );
        integral.resize( maxlen );
        for( size_type j=0; j        {
            unsigned int n = integral[j] + rhs[j] + c;
            c = n / 10;
            integral[j] = n % 10;
        }
        if( c != 0 )
            integral.push_back( (char)c );
    }
private:
    container integral;
    container fractional;
};
ostream& operator<<( ostream& os, const foo_& f )
{
    if( f.integral.empty() )
        os << '0';
    else for( foo_::size_type i=0; i        os << (foo_::value_type)(f.integral[ f.integral.size()-i-1 ]+'0');
    os << '.';
    if( f.fractional.empty() )
        os << '0';
    else for( foo_::size_type j=0; j        os << (foo_::value_type)(f.fractional[j]+'0');
    return os;
}
// 取位
bool GetBit_( const void* p, size_t n, size_t i )
{
    const unsigned char* _p = (const char unsigned *)p;
    const char _testendian[] = { 0, 1, 2, 3 };
    if( 0x00010203 == *(long*)&_testendian ) // big-endian
        return ( _p[n-1-i/8] & ( 1<<(i%8) ) ) > 0;
    else
        return ( _p[i/8] & ( 1<<(i%8) ) ) > 0;
}
// 输出浮点数, explen指数长度, validlen有效位长度, hb是否含隐含位
void printffloat_( int explen,int validlen,bool hb, const void* p )
{
    assert( 0 == ( 1 + explen + validlen ) % 8 );
    const size_t bytelen = ( 1 + explen + validlen ) / 8;
    bool sign = GetBit_( p, bytelen, validlen+explen ); // 符号
    long exp = 0;                                      // 阶码
    for( int i=validlen+explen-1; i>=validlen; --i )
    {
        exp = exp * 2 + GetBit_( p, bytelen, i );
    }
    exp -= ( (1<<(explen-1)) -1 );           // 阶码的固定偏移

    foo_ val(0.0);
    {
        foo_ bar(1.0);
        for( int i=validlen-exp-(hb?0:1); i        {
            if( i>=0 && GetBit_(p,bytelen,i) ) val.add( bar );
        }
        if( hb && exp>=0 ) val.add( bar );
    }
    {
        foo_ bar(0.5);
        for( int i=validlen-exp-1-(hb?0:1); i>=0; --i, bar.div2() )
        {
            if( hb && i==validlen ) val.add( bar );
            else if( i        }
    }

    cout << (sign?'-':'+') << val;
}
void printffloat( const float& f )
{
    printffloat_( 8, 23, true, &f );
}
void printffloat( const double& f )
{
    printffloat_( 11, 52, true, &f );
}
void printffloat( const long double& f )
{
    printffloat_( 15, 64, false, &f );
}

int main(int argc, char* argv[])
{
    cout << "float(123.456) = \n"; printffloat( 123.456f ); cout << '\n' << endl;
    cout << "double(123.456) = \n"; printffloat( 123.456 ); cout << '\n' << endl;
    unsigned char a[] = { 0x46, 0xB6, 0xF3, 0xFD, 0xD4, 0x78, 0xE9, 0xF6, 0x05, 0x40 };
    cout << "long double(123.456) = \n"; printffloat( *(long double*)&a ); cout << '\n' << endl;
    cout << "-----------------------------" << endl;

    cout << "float(0.0) = \n"; printffloat( 0.0f ); cout << '\n' << endl;
    cout << "double(0.0) = \n"; printffloat( 0.0 ); cout << '\n' << endl;
    unsigned char b[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    cout << "long double(0.0) = \n"; printffloat( *(long double*)&b ); cout << '\n' << endl;
    cout << "-----------------------------" << endl;

    cout << "float(max) = \n"; printffloat( numeric_limits::max() ); cout << '\n' << endl;
    cout << "double(max) = \n"; printffloat( numeric_limits::max() ); cout << '\n' << endl;
    unsigned char c[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F };
    cout << "long double(max) = \n"; printffloat( *(long double*)&c ); cout << '\n' << endl;
    cout << "-----------------------------" << endl;

    return 0;
}

输出结果:

float(123.456) =
+123.45600128173828125

double(123.456) =
+123.4560000000000030695446184836328029632568359375

long double(123.456) =
+123.45600000000000000255351295663786004297435283660888671875

-----------------------------
float(0.0) =
+0.0000000000000000000000000000000000000058774717541114375398436826861112283890933277838604376075437585313920862972736358642578125

double(0.0) =
+0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011125369292536006915451163586662020321096079902311659152766637084436022174069590979271415795062555102820336698655179055025762170807767300544280061926888594105653889967660011652398050737212918180359607825234712518671041876254033253083290794743602455899842958198242503179543850591524373998904438768749747257902258025254576999282912354093225567689679024960579905428830259962166760571761950743978498047956444458014963207555317331566968317387932565146858810236628158907428321754360614143188210224234057038069557385314008449266220550120807237108092835830752700771425423583764509515806613894483648536865616670434944915875339194234630463869889864293298274705456845477030682337843511993391576453404923086054623126983642578125

long double(0.0) =
+0.0

-----------------------------
float(max) =
+340282346638528859811704183484516925440.0

double(max) =
+179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0

long double(max) =
+1189731495357231765021263853030970205169063322294624200440323733891737005522970722616410290336528882853545697807495577314427443153670288434198125573853743678673593200706973263201915918282961524365529510646791086614311790632169778838896134786560600399148753433211454911160088679845154866512852340149773037600009125479393966223151383622417838542743917838138717805889487540575168226347659235576974805113725649020884855222494791399377585026011773549180099796226026859508558883608159846900235645132346594476384939859276456284579661772930407806609229102715046085388087959327781622986827547830768080040150694942303411728957777100335714010559775242124057347007386251660110828379119623008469277200965153500208474470792443848545912886723000619085126472111951361467527633519562927597957250278002980795904193139603021470997035276467445530922022679656280991498232083329641241038509239184734786121921697210543484287048353408113042573002216421348917347174234800714880751002064390517234247656004721768096486107994943415703476320643558624207443504424380566136017608837478165389027809576975977286860071487028287955567141404632615832623602762896316173978484254486860609948270867968048078702511858930838546584223040908805996294594586201903766048446790926002225410530775901065760671347200125846406957030257138960983757998926954553052368560758683179223113639519468850880771872104705203957587480013143131444254943919940175753169339392366881856189129931729104252921236835159922322050998001677102784035360140829296398115122877768135706045789343535451696539561254048846447169786893211671087229088082778350518228857646062218739702851655083720992349483334435228984751232753726636066213902281264706234075352071724058665079518217303463782631353393706774901950197841690441824738063162828586857741432581165364040218402724913393320949219498422442730427019873044536620350262386957804682003601447291997123095530057206141866974852846856186514832715974481203121946751686379343096189615107330065552421485195201762858595091051839472502863871632494167613804996319791441870254302706758495192008837915169401581740046711477877201459644461175204059453504764721807975761111720846273639279600339670470037613374509553184150073796412605047923251661354841291884211340823015473304754067072818763503617332908005951896325207071673904547777129682265206225651439919376804400292380903112437912614776255964694221981375146967079446870358004392507659451618379811859392049544036114915310782251072691486979809240946772142727012404377187409216756613634938900451232351668146089322400697993176017805338191849981933008410985993938760292601390911414526003720284872132411955424282101831204216104467404621635336900583664606591156298764745525068145003932941404131495400677602951005962253022823003631473824681059648442441324864573137437595096416168048024129351876204668135636877532814675538798871771836512893947195335061885003267607354388673368002074387849657014576090349857571243045102038730494854256702479339322809110526041538528994849203991091946129912491633289917998094380337879522093131466946149705939664152375949285890960489916121944989986384837022486672249148924678410206183364627416969576307632480235587975245253737035433882960862753427740016333434055083537048507374544819754722228975281083020898682633020285259923084168054539687911418297629988964576482765287504562854924265165217750799516259669229114977788962356670956627138482018191348321687995863652637620978285070099337294396784639879024914514222742527006363942327998483976739987154418554201562244154926653014515504685489258620276085761837129763358761215382565129633538141663949516556000264159186554850057052611431952919918807954522394649627635630178580896692226406235382898535867595990647008385687123810329591926494846250768992258419305480763620215089022149220528069842018350840586938493815498909445461977893029113576516775406232278298314033473276603952231603422824717528181818844304880921321933550869873395861276073670866652375555675803171490108477320096424318780070008797346032906278943553743564448851907191616455141155761939399690767415156402826543664026760095087523945507341556135867933066031744720924446513532366647649735400851967040771103640538150073486891798364049570606189535005089840913826869535090066783324472578712196604415284924840041850932811908963634175739897166596000759487800619164094854338758520657116541072260996288150123144377944008749301944744330784388995701842710004808305012177123560622895076269042856800047718893158089358515593863176652948089031267747029662545110861548958395087796755464137944895960527975209874813839762578592105756284401759349324162148339565350189196811389091843795734703269406342890087805846940352453479398080674273236297887100867175802531561302356064878709259865288416350972529537091114317204887747405539054009425375424119317944175137064689643861517718849867010341532542385911089624710885385808688837777258648564145934262121086647588489260031762345960769508849149662444156604419552086811989770240.0

-----------------------------

2011-02-15注:
当指数为0时,似乎不再使用“隐含位”
printf( "%g\n", 1ull );
printf( "%g\n", 2ull );
printf( "%g\n", 4ull );
使用VC9和MinGW4.5输出为
4.94066e-324
9.88131e-324
1.97626e-323
而我计算出来为
1.112536929253600938577939 e-308
1.112536929253601185610762 e-308
1.112536929253601679676408 e-308
似乎此时,不存在“隐含位”了,但不知道是否局限于windows和intel才如此

阅读(1502) | 评论(5) | 转发(0) |
给主人留下些什么吧!~~

网友评论2012-11-20 09:49:39

zlhex
# re: 精确打印浮点数 2005-09-16 20:06 arong  
××,浮点数本身就不精确,你打印“精确”有啥意义啊?  

arong说的不精确应该不是这个意思,很多人都说两个浮点数不能直接比较,就是因为他们认为浮点不精确。
他们认为的不精确是这么回事:
实数0.1(我随便举例的)用32位浮点数据来编码,不能像整数1用32位整型数据编码一样精确的表示,但是在计算机中a(0.1)和b(0.1)表示都是一样的,他们是精确的。

网友评论2012-11-20 09:49:27

周星星
谢谢!

网友评论2012-11-20 09:49:18

tinawan
bool GetBit_( const void* p, size_t n, size_t i )
{
    const unsigned char* _p = (const char unsigned *)p;
    const char _testendian[] = { 0, 1, 2, 3 };
    if( 0x0123 == *(long*)&_testendian ) // big-endian
        return ( _p[n-1-i/8] & ( 1<<(i%8) ) ) > 0;
    else
        return ( _p[i/8] & ( 1<<

网友评论2012-11-20 09:49:07

周星星
哦,浮点数不精确吗?这么说容易令新人产生疑惑 ^_^
float 用 123.45600128173828125 来表示 123.456 是不精确,误差10e-6级,但int用 123 来表示 123.456,误差是10e-1级,岂不是更不精确?但我们却从来不说int不精确,这是因为我们知道int不是实数容器,不强求她保留小数,但同样的是,float也不是实数容器呀,她只是一个有限数量的实数的集合。浮点数是绝对精确的,只是她不是实数而已。

网友评论2012-11-20 09:48:50

arong
××,浮点数本身就不精确,你打印“精确”有啥意义啊?