mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* sprintf.c (rb_str_format): support %a format. [ruby-dev:40650]
* missing/vsnprintf.c (BSD_vfprintf): ditto. * missing/vsnprintf.c (cvt): ditto. * util.c (BSD__hdtoa): added. This is 2-clause BSDL licensed by David Schultz and from FreeBSD. * LEGAL: add about hdtoa() in util.c. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27141 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
4d399f12d4
commit
12b2e16e21
6 changed files with 242 additions and 10 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
Thu Apr 1 13:30:12 2010 NARUSE, Yui <naruse@ruby-lang.org>
|
||||
|
||||
* sprintf.c (rb_str_format): support %a format. [ruby-dev:40650]
|
||||
|
||||
* missing/vsnprintf.c (BSD_vfprintf): ditto.
|
||||
|
||||
* missing/vsnprintf.c (cvt): ditto.
|
||||
|
||||
* util.c (BSD__hdtoa): added. This is 2-clause BSDL licensed
|
||||
by David Schultz and from FreeBSD.
|
||||
|
||||
* LEGAL: add about hdtoa() in util.c.
|
||||
|
||||
Thu Apr 1 13:24:12 2010 NARUSE, Yui <naruse@ruby-lang.org>
|
||||
|
||||
* object.c (rb_cstr_to_dbl): return 0.0 if hexadecimal and
|
||||
|
|
26
LEGAL
26
LEGAL
|
@ -123,6 +123,32 @@ win32/win32.[ch]:
|
|||
You may distribute under the terms of either the GNU General Public
|
||||
License or the Artistic License, as specified in the perl README file.
|
||||
|
||||
util.c (partly):
|
||||
|
||||
Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
random.c
|
||||
|
||||
This file is under the new-style BSD license.
|
||||
|
|
|
@ -559,7 +559,7 @@ BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap)
|
|||
struct __suio uio; /* output information: summary */
|
||||
struct __siov iov[NIOV];/* ... and individual io vectors */
|
||||
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
|
||||
char ox[2]; /* space for 0x hex-prefix */
|
||||
char ox[4]; /* space for 0x hex-prefix, hexadecimal's 1. */
|
||||
char *const ebuf = buf + sizeof(buf);
|
||||
#if SIZEOF_LONG > SIZEOF_INT
|
||||
long ln;
|
||||
|
@ -784,6 +784,11 @@ reswitch: switch (ch) {
|
|||
base = 10;
|
||||
goto number;
|
||||
#ifdef FLOATING_POINT
|
||||
case 'a':
|
||||
case 'A':
|
||||
if (prec >= 0)
|
||||
prec++;
|
||||
goto fp_begin;
|
||||
case 'e': /* anomalous precision */
|
||||
case 'E':
|
||||
if (prec != 0)
|
||||
|
@ -822,7 +827,12 @@ fp_begin: _double = va_arg(ap, double);
|
|||
else
|
||||
ch = 'g';
|
||||
}
|
||||
if (ch <= 'e') { /* 'e' or 'E' fmt */
|
||||
if (ch == 'a' || ch == 'A') {
|
||||
--expt;
|
||||
expsize = exponent(expstr, expt, ch + 'p' - 'a');
|
||||
size = expsize + ndig;
|
||||
}
|
||||
else if (ch <= 'e') { /* 'e' or 'E' fmt */
|
||||
--expt;
|
||||
expsize = exponent(expstr, expt, ch);
|
||||
size = expsize + ndig;
|
||||
|
@ -1048,7 +1058,20 @@ long_len:
|
|||
if ((flags & FPT) == 0) {
|
||||
PRINT(cp, fieldsz);
|
||||
} else { /* glue together f_p fragments */
|
||||
if (ch >= 'f') { /* 'f' or 'g' */
|
||||
if (ch == 'a' || ch == 'A') {
|
||||
ox[0] = '0';
|
||||
ox[1] = ch + ('x' - 'a');
|
||||
PRINT(ox, 2);
|
||||
if (ndig > 1 || flags & ALT) {
|
||||
ox[2] = *cp++;
|
||||
ox[3] = '.';
|
||||
PRINT(ox+2, 2);
|
||||
PRINT(cp, ndig-1);
|
||||
} else /* XpYYY */
|
||||
PRINT(cp, 1);
|
||||
PRINT(expstr, expsize);
|
||||
}
|
||||
else if (ch >= 'f') { /* 'f' or 'g' */
|
||||
if (_double == 0) {
|
||||
/* kludge for __dtoa irregularity */
|
||||
if (ndig <= 1 &&
|
||||
|
@ -1112,6 +1135,7 @@ error:
|
|||
#ifdef FLOATING_POINT
|
||||
|
||||
extern char *BSD__dtoa __P((double, int, int, int *, int *, char **));
|
||||
extern char *BSD__hdtoa(double, const char *, int, int *, int *, char **);
|
||||
|
||||
static char *
|
||||
cvt(value, ndigits, flags, sign, decpt, ch, length, buf)
|
||||
|
@ -1135,7 +1159,14 @@ cvt(value, ndigits, flags, sign, decpt, ch, length, buf)
|
|||
} else {
|
||||
*sign = '\000';
|
||||
}
|
||||
if (ch == 'a' || ch =='A') {
|
||||
digits = BSD__hdtoa(value,
|
||||
ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF",
|
||||
ndigits, decpt, &dsgn, &rve);
|
||||
}
|
||||
else {
|
||||
digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
|
||||
}
|
||||
memcpy(buf, digits, rve - digits);
|
||||
xfree(digits);
|
||||
rve = buf + (rve - digits);
|
||||
|
@ -1181,7 +1212,7 @@ exponent(p0, exp, fmtch)
|
|||
for (; t < expbuf + MAXEXP; *p++ = *t++);
|
||||
}
|
||||
else {
|
||||
*p++ = '0';
|
||||
if (fmtch & 15) *p++ = '0'; /* other than p or P */
|
||||
*p++ = to_char(exp);
|
||||
}
|
||||
return (int)(p - p0);
|
||||
|
|
16
sprintf.c
16
sprintf.c
|
@ -227,6 +227,10 @@ get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
|
|||
* | equal to the precision, or in dd.dddd form otherwise.
|
||||
* | The precision specifies the number of significant digits.
|
||||
* G | Equivalent to `g', but use an uppercase `E' in exponent form.
|
||||
* a | Convert floating point argument as [-]0xh.hhhhp[+-]dd,
|
||||
* | which is consisted from optional sign, "0x", fraction part
|
||||
* | as hexadecimal, "p", and exponential part as decimal.
|
||||
* A | Equivalent to `a', but use uppercase `X' and `P'.
|
||||
*
|
||||
* Field | Other Format
|
||||
* ------+--------------------------------------------------------------
|
||||
|
@ -244,7 +248,7 @@ get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
|
|||
* Flag | Applies to | Meaning
|
||||
* ---------+---------------+-----------------------------------------
|
||||
* space | bBdiouxX | Leave a space at the start of
|
||||
* | eEfgG | non-negative numbers.
|
||||
* | aAeEfgG | non-negative numbers.
|
||||
* | (numeric fmt) | For `o', `x', `X', `b' and `B', use
|
||||
* | | a minus sign with absolute value for
|
||||
* | | negative values.
|
||||
|
@ -255,19 +259,19 @@ get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
|
|||
* | | sprintf string.
|
||||
* ---------+---------------+-----------------------------------------
|
||||
* # | bBoxX | Use an alternative format.
|
||||
* | eEfgG | For the conversions `o', increase the precision
|
||||
* | aAeEfgG | For the conversions `o', increase the precision
|
||||
* | | until the first digit will be `0' if
|
||||
* | | it is not formatted as complements.
|
||||
* | | For the conversions `x', `X', `b' and `B'
|
||||
* | | on non-zero, prefix the result with ``0x'',
|
||||
* | | ``0X'', ``0b'' and ``0B'', respectively.
|
||||
* | | For `e', `E', `f', `g', and 'G',
|
||||
* | | For `a', `A', `e', `E', `f', `g', and 'G',
|
||||
* | | force a decimal point to be added,
|
||||
* | | even if no digits follow.
|
||||
* | | For `g' and 'G', do not remove trailing zeros.
|
||||
* ---------+---------------+-----------------------------------------
|
||||
* + | bBdiouxX | Add a leading plus sign to non-negative
|
||||
* | eEfgG | numbers.
|
||||
* | aAeEfgG | numbers.
|
||||
* | (numeric fmt) | For `o', `x', `X', `b' and `B', use
|
||||
* | | a minus sign with absolute value for
|
||||
* | | negative values.
|
||||
|
@ -275,7 +279,7 @@ get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
|
|||
* - | all | Left-justify the result of this conversion.
|
||||
* ---------+---------------+-----------------------------------------
|
||||
* 0 (zero) | bBdiouxX | Pad with zeros, not spaces.
|
||||
* | eEfgG | For `o', `x', `X', `b' and `B', radix-1
|
||||
* | aAeEfgG | For `o', `x', `X', `b' and `B', radix-1
|
||||
* | (numeric fmt) | is used for negative numbers formatted as
|
||||
* | | complements.
|
||||
* ---------+---------------+-----------------------------------------
|
||||
|
@ -983,6 +987,8 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)
|
|||
case 'G':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'a':
|
||||
case 'A':
|
||||
{
|
||||
VALUE val = GETARG();
|
||||
double fval;
|
||||
|
|
|
@ -191,6 +191,19 @@ class TestSprintf < Test::Unit::TestCase
|
|||
assert_equal(" Inf", sprintf("% 0e", 1.0/0.0), "moved from btest/knownbug")
|
||||
end
|
||||
|
||||
def test_float_hex
|
||||
assert_equal("-0x0p+0", sprintf("%a", -0.0))
|
||||
assert_equal("0x0p+0", sprintf("%a", 0.0))
|
||||
assert_equal("0x1p-1", sprintf("%a", 0.5))
|
||||
assert_equal("0x1p+0", sprintf("%a", 1.0))
|
||||
assert_equal("0x1p+1", sprintf("%a", 2.0))
|
||||
assert_equal("0x1.193ea7aad030ap+0", sprintf("%a", Math.log(3)))
|
||||
assert_equal("0X1.193EA7AAD030AP+0", sprintf("%A", Math.log(3)))
|
||||
assert_equal("0x1p+10", sprintf("%a", 1024))
|
||||
assert_equal("0x1.23456p+789", sprintf("%a", 3.704450999893983e+237))
|
||||
assert_equal("0x1p-1074", sprintf("%a", 4.9e-324))
|
||||
end
|
||||
|
||||
BSIZ = 120
|
||||
|
||||
def test_skip
|
||||
|
|
143
util.c
143
util.c
|
@ -3857,6 +3857,149 @@ ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *ar
|
|||
}
|
||||
}
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define DBL_MANH_SIZE 20
|
||||
#define DBL_MANL_SIZE 32
|
||||
#define INFSTR "Infinity"
|
||||
#define NANSTR "NaN"
|
||||
#define DBL_ADJ (DBL_MAX_EXP - 2)
|
||||
#define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1)
|
||||
#define dexp_get(u) ((int)(word0(u) >> Exp_shift) & ~Exp_msk1)
|
||||
#define dexp_set(u,v) (word0(u) = (((int)(word0(u)) & ~Exp_mask) | (v << Exp_shift)))
|
||||
#define dmanh_get(u) ((int)(word0(u) & Frac_mask))
|
||||
#define dmanl_get(u) ((int)word1(u))
|
||||
|
||||
|
||||
/*
|
||||
* This procedure converts a double-precision number in IEEE format
|
||||
* into a string of hexadecimal digits and an exponent of 2. Its
|
||||
* behavior is bug-for-bug compatible with dtoa() in mode 2, with the
|
||||
* following exceptions:
|
||||
*
|
||||
* - An ndigits < 0 causes it to use as many digits as necessary to
|
||||
* represent the number exactly.
|
||||
* - The additional xdigs argument should point to either the string
|
||||
* "0123456789ABCDEF" or the string "0123456789abcdef", depending on
|
||||
* which case is desired.
|
||||
* - This routine does not repeat dtoa's mistake of setting decpt
|
||||
* to 9999 in the case of an infinity or NaN. INT_MAX is used
|
||||
* for this purpose instead.
|
||||
*
|
||||
* Note that the C99 standard does not specify what the leading digit
|
||||
* should be for non-zero numbers. For instance, 0x1.3p3 is the same
|
||||
* as 0x2.6p2 is the same as 0x4.cp3. This implementation always makes
|
||||
* the leading digit a 1. This ensures that the exponent printed is the
|
||||
* actual base-2 exponent, i.e., ilogb(d).
|
||||
*
|
||||
* Inputs: d, xdigs, ndigits
|
||||
* Outputs: decpt, sign, rve
|
||||
*/
|
||||
char *
|
||||
BSD__hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign,
|
||||
char **rve)
|
||||
{
|
||||
U u;
|
||||
char *s, *s0;
|
||||
int bufsize;
|
||||
uint32_t manh, manl;
|
||||
|
||||
u.d = d;
|
||||
if (word0(u) & Sign_bit) {
|
||||
/* set sign for everything, including 0's and NaNs */
|
||||
*sign = 1;
|
||||
word0(u) &= ~Sign_bit; /* clear sign bit */
|
||||
}
|
||||
else
|
||||
*sign = 0;
|
||||
|
||||
switch (fpclassify(d)) {
|
||||
case FP_NORMAL:
|
||||
*decpt = dexp_get(u) - DBL_ADJ;
|
||||
break;
|
||||
case FP_ZERO:
|
||||
*decpt = 1;
|
||||
return (nrv_alloc("0", rve, 1));
|
||||
case FP_SUBNORMAL:
|
||||
u.d *= 5.363123171977039e+154 /* 0x1p514 */;
|
||||
*decpt = dexp_get(u) - (514 + DBL_ADJ);
|
||||
break;
|
||||
case FP_INFINITE:
|
||||
*decpt = INT_MAX;
|
||||
return (nrv_alloc(INFSTR, rve, sizeof(INFSTR) - 1));
|
||||
default: /* FP_NAN or unrecognized */
|
||||
*decpt = INT_MAX;
|
||||
return (nrv_alloc(NANSTR, rve, sizeof(NANSTR) - 1));
|
||||
}
|
||||
|
||||
/* FP_NORMAL or FP_SUBNORMAL */
|
||||
|
||||
if (ndigits == 0) /* dtoa() compatibility */
|
||||
ndigits = 1;
|
||||
|
||||
/*
|
||||
* If ndigits < 0, we are expected to auto-size, so we allocate
|
||||
* enough space for all the digits.
|
||||
*/
|
||||
bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
|
||||
s0 = rv_alloc(bufsize);
|
||||
|
||||
/* Round to the desired number of digits. */
|
||||
if (SIGFIGS > ndigits && ndigits > 0) {
|
||||
float redux = 1.0;
|
||||
int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG;
|
||||
dexp_set(u, offset);
|
||||
u.d += redux;
|
||||
u.d -= redux;
|
||||
*decpt += dexp_get(u) - offset;
|
||||
}
|
||||
|
||||
manh = dmanh_get(u);
|
||||
manl = dmanl_get(u);
|
||||
*s0 = '1';
|
||||
for (s = s0 + 1; s < s0 + bufsize; s++) {
|
||||
*s = xdigs[(manh >> (DBL_MANH_SIZE - 4)) & 0xf];
|
||||
manh = (manh << 4) | (manl >> (DBL_MANL_SIZE - 4));
|
||||
manl <<= 4;
|
||||
}
|
||||
|
||||
/* If ndigits < 0, we are expected to auto-size the precision. */
|
||||
if (ndigits < 0) {
|
||||
for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--)
|
||||
;
|
||||
}
|
||||
|
||||
s = s0 + ndigits;
|
||||
*s = '\0';
|
||||
if (rve != NULL)
|
||||
*rve = s;
|
||||
return (s0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if 0
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue