[前][次][番号順一覧][スレッド一覧]

ruby-changes:15259

From: naruse <ko1@a...>
Date: Thu, 1 Apr 2010 13:33:18 +0900 (JST)
Subject: [ruby-changes:15259] Ruby:r27141 (trunk): * sprintf.c (rb_str_format): support %a format.

naruse	2010-04-01 13:32:57 +0900 (Thu, 01 Apr 2010)

  New Revision: 27141

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=27141

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/LEGAL
    trunk/missing/vsnprintf.c
    trunk/sprintf.c
    trunk/test/ruby/test_sprintf.rb
    trunk/util.c

Index: LEGAL
===================================================================
--- LEGAL	(revision 27140)
+++ LEGAL	(revision 27141)
@@ -123,6 +123,32 @@
     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@F...>
+   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.
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 27140)
+++ ChangeLog	(revision 27141)
@@ -1,3 +1,16 @@
+Thu Apr  1 13:30:12 2010  NARUSE, Yui  <naruse@r...>
+
+	* 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@r...>
 
 	* object.c (rb_cstr_to_dbl): return 0.0 if hexadecimal and
Index: sprintf.c
===================================================================
--- sprintf.c	(revision 27140)
+++ sprintf.c	(revision 27141)
@@ -227,6 +227,10 @@
  *            | 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 @@
  *    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 @@
  *             |               | 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 @@
  *    -        | 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 @@
 	  case 'G':
 	  case 'e':
 	  case 'E':
+	  case 'a':
+	  case 'A':
 	    {
 		VALUE val = GETARG();
 		double fval;
Index: util.c
===================================================================
--- util.c	(revision 27140)
+++ util.c	(revision 27141)
@@ -3857,6 +3857,149 @@
     }
 }
 
+/*-
+ * Copyright (c) 2004-2008 David Schultz <das@F...>
+ * 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
 {
Index: test/ruby/test_sprintf.rb
===================================================================
--- test/ruby/test_sprintf.rb	(revision 27140)
+++ test/ruby/test_sprintf.rb	(revision 27141)
@@ -191,6 +191,19 @@
     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
Index: missing/vsnprintf.c
===================================================================
--- missing/vsnprintf.c	(revision 27140)
+++ missing/vsnprintf.c	(revision 27141)
@@ -559,7 +559,7 @@
 	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 @@
 			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,8 +827,13 @@
 				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;
 				if (ndig > 1 || flags & ALT)
@@ -1048,7 +1058,20 @@
 		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 @@
 #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 @@
 	} else {
 	    *sign = '\000';
 	}
-	digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
+	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 @@
 		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);

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]