1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

F style output(like 1234.56789) implemented to to_s method.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4356 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shigek 2003-08-08 15:31:27 +00:00
parent 0a0c87bb12
commit 606c473683
4 changed files with 269 additions and 110 deletions

View file

@ -197,7 +197,7 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &dummy);
GUARD_OBJ(vp,GetVpValue(self,1));
sprintf(sz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
psz = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp)+strlen(sz));
psz = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E")+strlen(sz));
sprintf(psz,"%s",sz);
VpToString(vp, psz+strlen(psz), 0);
return rb_str_new2(psz);
@ -233,13 +233,17 @@ BigDecimal_mode(VALUE self, VALUE which, VALUE val)
{
unsigned long f,fo;
if(TYPE(which)!=T_FIXNUM) return Qnil;
Check_Type(which, T_FIXNUM);
f = (unsigned long)FIX2INT(which);
if(f&VP_EXCEPTION_ALL) {
/* Exception mode setting */
fo = VpGetException();
if(val!=Qfalse && val!=Qtrue) return Qnil;
if(val==Qnil) return INT2FIX(fo);
if(val!=Qfalse && val!=Qtrue) {
rb_raise(rb_eTypeError, "The second argument must be true or false.");
return Qnil; /* Not reached */
}
if(f&VP_EXCEPTION_INFINITY) {
VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_INFINITY):
(fo&(~VP_EXCEPTION_INFINITY))));
@ -248,14 +252,22 @@ BigDecimal_mode(VALUE self, VALUE which, VALUE val)
VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN):
(fo&(~VP_EXCEPTION_NaN))));
}
fo = VpGetException();
return INT2FIX(fo);
}
if(VP_ROUND_MODE==f) {
/* Rounding mode setting */
if(TYPE(val)!=T_FIXNUM) return Qnil;
fo = VpGetRoundMode();
if(val==Qnil) return INT2FIX(fo);
Check_Type(val, T_FIXNUM);
if(!VpIsRoundMode(FIX2INT(val))) {
rb_raise(rb_eTypeError, "Invalid rounding mode.");
return Qnil;
}
fo = VpSetRoundMode((unsigned long)FIX2INT(val));
return INT2FIX(fo);
}
rb_raise(rb_eTypeError, "The first argument for BigDecimal#mode is invalid.");
return Qnil;
}
@ -919,13 +931,14 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
Check_Type(vLoc, T_FIXNUM);
iLoc = FIX2INT(vLoc);
break;
case 2:{
int sws = sw;
case 2:
Check_Type(vLoc, T_FIXNUM);
iLoc = FIX2INT(vLoc);
Check_Type(vRound, T_FIXNUM);
sw = VpSetRoundMode(FIX2INT(vRound));
VpSetRoundMode(sws);
sw = FIX2INT(vRound);
if(!VpIsRoundMode(sw)) {
rb_raise(rb_eTypeError, "Invalid rounding mode.");
return Qnil;
}
break;
}
@ -1024,20 +1037,45 @@ static VALUE
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
{
ENTER(5);
int fmt=0; /* 0:E format */
Real *vp;
char *psz;
char ch;
U_LONG nc;
S_INT mc = 0;
VALUE f;
GUARD_OBJ(vp,GetVpValue(self,1));
nc = VpNumOfChars(vp)+1;
if(rb_scan_args(argc,argv,"01",&f)==1) {
mc = GetPositiveInt(f);
nc += (nc + mc - 1) / mc + 1;
if(TYPE(f)==T_STRING) {
SafeStringValue(f);
psz = RSTRING(f)->ptr;
while(ch=*psz++) {
if(!ISDIGIT(ch)) {
if(ch=='F' || ch=='f') fmt = 1; /* F format */
break;
}
mc = mc * 10 + ch - '0';
}
} else {
mc = GetPositiveInt(f);
}
if(fmt) {
nc = VpNumOfChars(vp,"F");
} else {
nc = VpNumOfChars(vp,"E");
}
if(mc>0) nc += (nc + mc - 1) / mc + 1;
}
psz = ALLOCA_N(char,(unsigned int)nc);
if(fmt) {
VpToFString(vp, psz, mc);
} else {
VpToString (vp, psz, mc);
}
return rb_str_new2(psz);
}
@ -1052,7 +1090,7 @@ BigDecimal_split(VALUE self)
char *psz1;
GUARD_OBJ(vp,GetVpValue(self,1));
psz1 = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp));
psz1 = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E"));
VpSzMantissa(vp,psz1);
s = 1;
if(psz1[0]=='-') {
@ -1087,7 +1125,7 @@ BigDecimal_inspect(VALUE self)
char *pszAll;
GUARD_OBJ(vp,GetVpValue(self,1));
nc = VpNumOfChars(vp);
nc = VpNumOfChars(vp,"E");
nc +=(nc + 9) / 10;
psz1 = ALLOCA_N(char,nc);
@ -1298,7 +1336,7 @@ Init_bigdecimal(void)
rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE",INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
/* instance methods */
rb_define_method(rb_cBigDecimal, "prec", BigDecimal_prec, 0);
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
@ -1478,14 +1516,21 @@ VpGetRoundMode(void)
return gfRoundMode;
}
VP_EXPORT unsigned long
VpSetRoundMode(unsigned long n)
VP_EXPORT int
VpIsRoundMode(unsigned long n)
{
if(n==VP_ROUND_UP || n!=VP_ROUND_DOWN ||
n==VP_ROUND_HALF_UP || n!=VP_ROUND_HALF_DOWN ||
n==VP_ROUND_CEIL || n!=VP_ROUND_FLOOR ||
n==VP_ROUND_HALF_EVEN
) gfRoundMode = n;
) return 1;
return 0;
}
VP_EXPORT unsigned long
VpSetRoundMode(unsigned long n)
{
if(VpIsRoundMode(n)) gfRoundMode = n;
return gfRoundMode;
}
@ -1722,14 +1767,35 @@ NaN:
*/
/*
* returns number of chars needed to represent vp.
* returns number of chars needed to represent vp in specified format.
*/
VP_EXPORT U_LONG
VpNumOfChars(Real *vp)
VpNumOfChars(Real *vp,char *pszFmt)
{
S_INT ex;
U_LONG nc;
if(vp == NULL) return BASE_FIG*2+6;
if(!VpIsDef(vp)) return 32; /* not sure,may be OK */
return BASE_FIG *(vp->Prec + 2)+6; /* 3: sign + exponent chars */
switch(*pszFmt)
{
case 'F':
nc = BASE_FIG*(vp->Prec + 1)+2;
ex = vp->exponent;
if(ex<0) {
nc += BASE_FIG*(-ex);
} else {
if(ex > (S_INT)vp->Prec) {
nc += BASE_FIG*(ex - (S_INT)vp->Prec);
}
}
break;
case 'E':
default:
nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
}
return nc;
}
/*
@ -2381,9 +2447,9 @@ VpSetPTR(Real *a, Real *b, Real *c, U_LONG *a_pos, U_LONG *b_pos, U_LONG *c_pos,
right_word = Max((a->Prec),left_word);
left_word =(c->MaxPrec) - 1; /* -1 ... prepare for round up */
/*
* check if 'round off' is needed.
* check if 'round' is needed.
*/
if(right_word > left_word) { /* round off ? */
if(right_word > left_word) { /* round ? */
/*---------------------------------
* Actual size of a = xxxxxxAxx
* Actual size of b = xxxBxxxxx
@ -3036,7 +3102,8 @@ VpFormatSt(char *psz,S_INT fFmt)
U_LONG i;
S_INT nf = 0;
char ch;
int fDot = 0;
if(fFmt<=0) return;
ie = strlen(psz);
for(i = 0; i < ie; ++i) {
@ -3044,10 +3111,8 @@ VpFormatSt(char *psz,S_INT fFmt)
if(!ch) break;
if(ch == '.') {
nf = 0;
fDot = 1;
continue;
}
if(!fDot) continue;
if(ch == 'E') break;
nf++;
if(nf > fFmt) {
@ -3123,6 +3188,29 @@ VpSzMantissa(Real *a,char *psz)
}
}
VP_EXPORT int
VpToSpecialString(Real *a,char *psz)
{
if(VpIsNaN(a)) {
sprintf(psz,SZ_NaN);
return 1;
}
if(VpIsPosInf(a)) {
sprintf(psz,SZ_INF);
return 1;
}
if(VpIsNegInf(a)) {
sprintf(psz,SZ_NINF);
return 1;
}
if(VpIsZero(a)) {
if(VpIsPosZero(a)) sprintf(psz, "0.0");
else sprintf(psz, "-0.0");
return 1;
}
return 0;
}
VP_EXPORT void
VpToString(Real *a,char *psz,int fFmt)
{
@ -3131,21 +3219,10 @@ VpToString(Real *a,char *psz,int fFmt)
char *pszSav = psz;
S_LONG ex;
if(VpIsNaN(a)) {
sprintf(psz,SZ_NaN);
return;
}
if(VpIsPosInf(a)) {
sprintf(psz,SZ_INF);
return;
}
if(VpIsNegInf(a)) {
sprintf(psz,SZ_NINF);
return;
}
if(VpToSpecialString(a,psz)) return;
ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
if(!VpIsZero(a)) {
if(VpGetSign(a) < 0) *psz++ = '-';
*psz++ = '0';
*psz++ = '.';
@ -3173,10 +3250,56 @@ VpToString(Real *a,char *psz,int fFmt)
}
while(psz[-1]=='0') *(--psz) = 0;
sprintf(psz, "E%ld", ex);
} else {
if(VpIsPosZero(a)) sprintf(psz, "0.0");
else sprintf(psz, "-0.0");
if(fFmt) VpFormatSt(pszSav, fFmt);
}
VP_EXPORT void
VpToFString(Real *a,char *psz,int fFmt)
{
U_LONG i;
U_LONG n, m, e, nn;
char *pszSav = psz;
S_LONG ex;
if(VpToSpecialString(a,psz)) return;
if(VpGetSign(a) < 0) *psz++ = '-';
n = a->Prec;
ex = a->exponent;
if(ex<=0) {
*psz++ = '0';*psz++ = '.';
while(ex<0) {
for(i=0;i<BASE_FIG;++i) *psz++ = '0';
++ex;
}
ex = -1;
}
for(i=0;i < n;++i) {
--ex;
if(i==0 && ex >= 0) {
sprintf(psz, "%lu", a->frac[i]);
psz += strlen(psz);
} else {
m = BASE1;
e = a->frac[i];
while(m) {
nn = e / m;
*psz++ = nn + '0';
e = e - nn * m;
m /= 10;
}
}
if(ex == 0) *psz++ = '.';
}
while(--ex>=0) {
m = BASE;
while(m/=10) *psz++ = '0';
if(ex == 0) *psz++ = '.';
}
*psz = 0;
while(psz[-1]=='0') *(--psz) = 0;
if(psz[-1]=='.') sprintf(psz, "0");
if(fFmt) VpFormatSt(pszSav, fFmt);
}

View file

@ -122,12 +122,13 @@ VP_EXPORT U_LONG VpGetPrecLimit(void);
VP_EXPORT U_LONG VpSetPrecLimit(U_LONG n);
/* Round mode */
VP_EXPORT int VpIsRoundMode(unsigned long n);
VP_EXPORT unsigned long VpGetRoundMode(void);
VP_EXPORT unsigned long VpSetRoundMode(unsigned long n);
VP_EXPORT int VpException(unsigned short f,char *str,int always);
VP_EXPORT int VpIsNegDoubleZero(double v);
VP_EXPORT U_LONG VpNumOfChars(Real *vp);
VP_EXPORT U_LONG VpNumOfChars(Real *vp,char *pszFmt);
VP_EXPORT U_LONG VpInit(U_LONG BaseVal);
VP_EXPORT void *VpMemAlloc(U_LONG mb);
VP_EXPORT void VpFree(Real *pv);
@ -139,7 +140,9 @@ VP_EXPORT int VpDivd(Real *c,Real *r,Real *a,Real *b);
VP_EXPORT int VpComp(Real *a,Real *b);
VP_EXPORT S_LONG VpExponent10(Real *a);
VP_EXPORT void VpSzMantissa(Real *a,char *psz);
VP_EXPORT int VpToSpecialString(Real *a,char *psz);
VP_EXPORT void VpToString(Real *a,char *psz,int fFmt);
VP_EXPORT void VpToFString(Real *a,char *psz,int fFmt);
VP_EXPORT int VpCtoV(Real *a,char *int_chr,U_LONG ni,char *frac,U_LONG nf,char *exp_chr,U_LONG ne);
VP_EXPORT int VpVtoD(double *d,S_LONG *e,Real *m);
VP_EXPORT void VpDtoV(Real *m,double d);

View file

@ -148,8 +148,8 @@ EXCEPTION_ZERODIVIDE results to +Infinity or -Infinity<BR>
</BLOCKQUOTE>
EXCEPTION_INFINITY,EXCEPTION_OVERFLOW, and EXCEPTION_ZERODIVIDE are
currently the same.<BR>
The return value of mode method is the previous value set.<BR>
nil is returned if any argument is wrong.<BR>
The return value of mode method is the value set.<BR>
If nil is specified for the second argument,then current setting is returned.<BR>
Suppose the return value of the mode method is f,then
f &amp; BigDecimal::EXCEPTION_NaN !=0 means EXCEPTION_NaN is set to on.
<P>
@ -169,8 +169,7 @@ where flag must be one of:
<TR><TD>ROUND_CEILING</TD><TD>round towards positive infinity(ceil).</TD></TR>
<TR><TD>ROUND_FLOOR</TD><TD>round towards negative infinity(floor).</TD></TR>
</TABLE>
New rounding mode is returned,nil is returned if any argument is not an integer.
Bad specification is ignored.<BR>
New rounding mode is returned. If nil is specified for the second argument,then current setting is returned.<BR>
The digit location for rounding operation can not be specified by this mode method,
use truncate/round/ceil/floor/add/sub/mult/div mthods for each instance instead.
</BLOCKQUOTE>
@ -359,10 +358,27 @@ If a is Infinity or NaN,then i becomes to nil.
</BLOCKQUOTE>
<LI><B>to_s[(n)]</B></LI><BLOCKQUOTE>
converts to string(results look like "0.xxxxxEn").<BR>
s = a.to_s<BR>
If n is given,then a space is inserted after every n digits for readability.<BR>
s = a.to_s(n)
converts to string(default results look like "0.xxxxxEn").
<CODE><PRE>
BigDecimal("1.23456").to_s # ==> "0.123456E1"
</PRE></CODE>
If n(>0) is given,then a space is inserted to each of two parts divided by the decimal point
after every n digits for readability.
<CODE><PRE>
BigDecimal("0.1234567890123456789").to_s(10) # ==> "0.1234567890 123456789E0"
</PRE></CODE>
n can be an string representing a positive integer number.
<CODE><PRE>
BigDecimal("0.1234567890123456789").to_s("10") # ==> "0.1234567890 123456789E0"
</PRE></CODE>
At the end of the string,'E'(or 'e') or 'F'(or 'f') can be specified to change
number representation.
<CODE><PRE>
BigDecimal("1234567890.123456789").to_s("E") # ==> "0.1234567890123456789E10"
BigDecimal("1234567890.123456789").to_s("F") # ==> "1234567890.123456789"
BigDecimal("1234567890.123456789").to_s("5E") # ==> "0.12345 67890 12345 6789E10"
BigDecimal("1234567890.123456789").to_s("5F") # ==> "12345 67890.12345 6789"
</PRE></CODE>
</BLOCKQUOTE>
<LI><B>exponent</B></LI><BLOCKQUOTE>
@ -371,8 +387,8 @@ n = a.exponent <BR>
means a = 0.xxxxxxx*10**n.
</BLOCKQUOTE>
<LI><B>prec</B></LI><BLOCKQUOTE>
n,m = a.prec <BR>
<LI><B>precs</B></LI><BLOCKQUOTE>
n,m = a.precs <BR>
prec returns number of significant digits (n) and maximum number of
significant digits (m) of a.
</BLOCKQUOTE>

View file

@ -157,10 +157,10 @@ EXCEPTION_ZERODIVIDE
</BLOCKQUOTE>
EXCEPTION_INFINITY、EXCEPTION_OVERFLOW、EXCEPTION_ZERODIVIDE
は今のところ同じです。<BR>
戻り値は、設定の値です。「値」の意味は、例えば
戻り値は、設定の値です。「値」の意味は、例えば
BigDecimal::EXCEPTION_NaNと「値」の & が ゼロ以外ならば
EXCEPTION_NaNが設定されているという意味です。<BR>
引数に正しくないものが指定された場合は nil が返ります。
第2引数に nil を指定すると、現状の設定値が返ります。
<P>
<B>[丸め処理指定]</B><P>
@ -181,8 +181,7 @@ f = BigDecimal::mode(BigDecimal::ROUND_MODE,flag)
</TABLE>
戻り値は指定後の flag の値です。
引数に数値以外が指定された場合は nil が返ります。正しくない ROUND_MODE が指定されたときは
無視され、現状の ROUND_MODE が返ります。<BR>
第2引数に nil を指定すると、現状の設定値が返ります。
mode メソッドでは丸め操作の位置をユーザが指定することはできません。
丸め操作と位置を自分で制御したい場合は truncate/round/ceil/floor や
add/sub/mult/div といったインスタンスメソッドを使用して下さい。
@ -375,10 +374,28 @@ Float
ください。
</BLOCKQUOTE>
<LI><B>to_s[(n)]</B></LI><BLOCKQUOTE>
文字列に変換します("0.xxxxxEn"の形になります)。<BR>
s = a.to_s<BR>
n が指定されたときは、仮数部分を n 桁毎に空白で区切ります。<BR>
s = a.to_s(n)
文字列に変換します(デフォルトは "0.xxxxxEn" の形になります)。
<CODE><PRE>
BigDecimal("1.23456").to_s # ==> "0.123456E1"
</PRE></CODE>
引数 n に正の整数が指定されたときは、少数点で分けられる左右部分を、それぞれ n 桁毎
に空白で区切ります。
<CODE><PRE>
BigDecimal("0.1234567890123456789").to_s(10) # ==> "0.1234567890 123456789E0"
</PRE></CODE>
引数 n に正の整数を表す文字列を指定することもできます。
<CODE><PRE>
BigDecimal("0.1234567890123456789").to_s("10") # ==> "0.1234567890 123456789E0"
</PRE></CODE>
さらに文字列の最後に E(または e) か F(または f) を指定することで、以下のように
表示形式を変更することができます。
<CODE><PRE>
BigDecimal("1234567890.123456789").to_s("E") # ==> "0.1234567890123456789E10"
BigDecimal("1234567890.123456789").to_s("F") # ==> "1234567890.123456789"
BigDecimal("1234567890.123456789").to_s("5E") # ==> "0.12345 67890 12345 6789E10"
BigDecimal("1234567890.123456789").to_s("5F") # ==> "12345 67890.12345 6789"
</PRE></CODE>
</BLOCKQUOTE>
<LI><B>exponent</B></LI><BLOCKQUOTE>
指数部を整数値で返します。
@ -386,8 +403,8 @@ n = a.exponent <BR>
は a の値が 0.xxxxxxx*10**n を意味します。
</BLOCKQUOTE>
<LI><B>prec</B></LI><BLOCKQUOTE>
n,m = a.prec<BR>
<LI><B>precs</B></LI><BLOCKQUOTE>
n,m = a.precs<BR>
a の有効数字 (n) と最大有効数字 (m) の配列を返します。
</BLOCKQUOTE>