diff options
| author | Masaki Muranaka <[email protected]> | 2013-03-17 02:13:32 +0900 |
|---|---|---|
| committer | Masaki Muranaka <[email protected]> | 2013-03-17 02:31:40 +0900 |
| commit | 9be437c6d5074ded76417792ab22b78eeb0351aa (patch) | |
| tree | 69e399a5306819771479880891651e93a720e516 /src/numeric.c | |
| parent | fd69e271bb168bab7994437aab211bd08b2fef15 (diff) | |
| download | mruby-9be437c6d5074ded76417792ab22b78eeb0351aa.tar.gz mruby-9be437c6d5074ded76417792ab22b78eeb0351aa.zip | |
Add a new function mrb_flo_to_str(). Use it instead of sprintf() as possible.
Diffstat (limited to 'src/numeric.c')
| -rw-r--r-- | src/numeric.c | 115 |
1 files changed, 98 insertions, 17 deletions
diff --git a/src/numeric.c b/src/numeric.c index 0bfd09b6e..2801811c3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -163,6 +163,99 @@ num_abs(mrb_state *mrb, mrb_value num) * representation. */ +mrb_value +mrb_flo_to_str(mrb_state *mrb, mrb_float n, int max_digit) +{ + mrb_value result; + + if (max_digit > 40) { + mrb_raise(mrb, E_RANGE_ERROR, "Too large max_digit."); + } + + if (isnan(n)) { + result = mrb_str_new(mrb, "NaN", 3); + } + else if (isinf(n)) { + if (n < 0) { + result = mrb_str_new(mrb, "-inf", 4); + } + else { + result = mrb_str_new(mrb, "inf", 3); + } + } + else { + int digit; + int m; + int exp; + int e = 0; + char s[48]; + char *c = &s[0]; + + if (n < 0) { + n = -n; + *(c++) = '-'; + } + + exp = log10(n); + + if ((exp < 0 ? -exp : exp) > max_digit) { + /* exponent representation */ + e = 1; + m = exp; + if (m < 0) { + m -= 1; + } + n = n / pow(10.0, m); + m = 0; + } + else { + /* un-exponent (normal) representation */ + m = exp; + if (m < 0) { + m = 0; + } + } + + /* puts digits */ + while (max_digit >= 0) { + mrb_float weight = pow(10.0, m); + digit = floor(n / weight + FLT_EPSILON); + *(c++) = '0' + digit; + n -= (digit * weight); + max_digit--; + if (m-- == 0) { + *(c++) = '.'; + } + else if (m < -1 && n < FLT_EPSILON) { + break; + } + } + + if (e) { + *(c++) = 'e'; + if (exp > 0) { + *(c++) = '+'; + } else { + *(c++) = '-'; + exp = -exp; + } + + if (exp >= 100) { + mrb_raise(mrb, E_RANGE_ERROR, "Too large expornent."); + } + + *(c++) = '0' + exp / 10; + *(c++) = '0' + exp % 10; + } + + *c = '\0'; + + result = mrb_str_new(mrb, &s[0], c - &s[0]); + } + + return result; +} + /* 15.2.9.3.16(x) */ /* * call-seq: @@ -177,27 +270,15 @@ num_abs(mrb_state *mrb, mrb_value num) static mrb_value flo_to_s(mrb_state *mrb, mrb_value flt) { - char buf[32]; - int n; - - mrb_float value = mrb_float(flt); - - if (isinf(value)) { - static const char s[2][5] = { "-inf", "inf" }; - static const int n[] = { 4, 3 }; - int idx; - idx = (value < 0) ? 0 : 1; - return mrb_str_new(mrb, s[idx], n[idx]); - } else if(isnan(value)) - return mrb_str_new(mrb, "NaN", 3); + int max_digit; #ifdef MRB_USE_FLOAT - n = sprintf(buf, "%.7g", value); + max_digit = 7; #else - n = sprintf(buf, "%.14g", value); + max_digit = 14; #endif - assert(n >= 0); - return mrb_str_new(mrb, buf, n); + + return mrb_flo_to_str(mrb, mrb_float(flt), max_digit); } /* 15.2.9.3.2 */ |
