2009年5月15日金曜日

文字列をRubyっぽく数値(浮動小数)変換する

整数変換を作ったついでに浮動小数も作ってみた。
整数変換の方は整理できたけど、こっちは落書きみたいだ・・・

float.cpp
namespace Float {

double base(double direction, int volume)
{
double position = 1.0;
for(int i = 0; i < volume; ++i)
{
position *= direction;
}
return position;
}

double to_f(const char* itr, const char* end)
{
if(itr == end){ return 0.0; } // NG

double flag = 1.0;
switch(*itr)
{
case '-':
flag = -1.0;
// no break needed
case '+':
while(true)
{
++itr;
if(itr == end){ return 0.0; } // NG
if(*itr != ' '){ break; }
}
break;
}

double mantissa = 0.0;

if(Integer::DecimalNumber::acceptable(*itr))
{
mantissa = Integer::DecimalNumber::to_i(*itr);
while(true)
{
++itr;
if(itr == end){ return flag * mantissa; } // OK
if(*itr == '_')
{
++itr;
if(itr == end){ return flag * mantissa; } // OK (with garbage)
}
if(!Integer::DecimalNumber::acceptable(*itr))
{
break;
}
mantissa = mantissa * 10.0 + Integer::DecimalNumber::to_i(*itr);
}
}

if('.' == *itr)
{
++itr;
if(itr == end){ return flag * mantissa; } // OK (with garbage)

if(!Integer::DecimalNumber::acceptable(*itr))
{
return flag * mantissa; // OK (with garbage)
}

double position = 0.1;
while(true)
{
mantissa += position * Integer::DecimalNumber::to_i(*itr);
++itr;
if(itr == end){ break; }
if('_' == *itr)
{
++itr;
if(itr == end){ break; }
}
if(!Integer::DecimalNumber::acceptable(*itr)){ break; }
position *= 0.1;
}
}

if('e' != *itr && 'E' != *itr){ return flag * mantissa; }

++itr;
if(itr == end){ return flag * mantissa; }

if('-' == *itr)
return flag * mantissa * base(0.1, Integer::parse_first<Integer::DecimalNumber>(itr, end));

if('+' == *itr)
return flag * mantissa * base(10.0, Integer::parse_first<Integer::DecimalNumber>(itr, end));

if(Integer::DecimalNumber::acceptable(*itr))
return flag * mantissa * base(10.0, Integer::parse_last<Integer::DecimalNumber>(itr, end));

return flag * mantissa;
}
}

0 件のコメント:

コメントを投稿