[#40528] [Feature #2833] 絵文字エンコーディングの提案 — Kenta Murata <redmine@...>

Feature #2833: 絵文字エンコーディングの提案

32 messages 2010/03/02
[#40530] Re: [Feature #2833] 絵文字エンコーディングの提案 — Yukihiro Matsumoto <matz@...> 2010/03/02

まつもと ゆきひろです

[#40597] Re: [ruby-list:46898] 重複組合せは組込みにならないのでしょうか? — "KISHIMOTO, Makoto" <[email protected]>

きしもとです

17 messages 2010/03/12
[#40598] Re: [ruby-list:46898] 重複組合せは組込みにならないのでしょうか? — Yukihiro Matsumoto <matz@...> 2010/03/12

まつもと ゆきひろです

[#40601] Re: [ruby-list:46898] 重複組合せは組込みにならないのでしょうか? — Yusuke ENDOH <mame@...> 2010/03/12

遠藤です。

[#40608] Re: 組込みの重複順列・重複組合せ — "KISHIMOTO, Makoto" <[email protected]> 2010/03/13

> 同様に、repeated_permutation/combination のデフォルト引数にも反対

[#40610] Re: 組込みの重複順列・重複組合せ — Yukihiro Matsumoto <matz@...> 2010/03/13

まつもと ゆきひろです

[#40641] [Bug #2965] method `===' called on hidden T_STRING object (NotImplementedError) — Kenta Murata <redmine@...>

Bug #2965: method `===' called on hidden T_STRING object (NotImplementedError)

12 messages 2010/03/15

[#40649] [Feature #2968] 数値の正負を返すメソッド — Yui NARUSE <redmine@...>

Feature #2968: 数値の正負を返すメソッド

17 messages 2010/03/15

[#40650] [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — Yui NARUSE <redmine@...>

Feature #2969: String#to_f が -h.hhh±pd を解釈できるように

38 messages 2010/03/15
[#40728] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — Tadayoshi Funaba <tadf@...> 2010/03/22

質問ですが、この形式は入力だけでなく、なんらかの方法で出力でも利用でき

[#40732] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — "NARUSE, Yui" <naruse@...> 2010/03/22

成瀬です。

[#40736] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — Tadayoshi Funaba <tadf@...> 2010/03/23

> String#to_f は従来から指数表記を許していたので、

[#40738] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — "NARUSE, Yui" <naruse@...> 2010/03/23

成瀬です。

[#40745] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — Tadayoshi Funaba <tadf@...> 2010/03/24

> to_i がデフォルトで prefix を見ないのは、0377 のような、

[#40747] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — "NARUSE, Yui" <naruse@...> 2010/03/24

成瀬です。

[#40749] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — Tadayoshi Funaba <tadf@...> 2010/03/24

> 先のパッチの対象関数が ruby_strtod である通り、

[#40759] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — "NARUSE, Yui" <naruse@...> 2010/03/25

成瀬です。

[#40762] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — Tadayoshi Funaba <tadf@...> 2010/03/25

> strtod(3) の解釈対象に含まれていない 2 進や 8 進を否定することが、

[#40763] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — "NARUSE, Yui" <naruse@...> 2010/03/25

(2010/03/26 3:05), Tadayoshi Funaba wrote:

[#40764] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — Tadayoshi Funaba <tadf@...> 2010/03/25

> なぜ同じなのでしょう。

[#40782] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — "NARUSE, Yui" <naruse@...> 2010/03/26

(2010/03/26 4:02), Tadayoshi Funaba wrote:

[#40786] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — KOSAKI Motohiro <kosaki.motohiro@...> 2010/03/27

>> strtod(3) を参考にしたり、影響されたりすることは普通にあるとは思います

[#40788] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように — "NARUSE, Yui" <naruse@...> 2010/03/27

(2010/03/27 18:19), KOSAKI Motohiro wrote:

[#40695] keiju, please check tickets assigned to you — Yusuke ENDOH <mame@...>

いしつかさん

15 messages 2010/03/18

[#40779] [Feature #3018] UNINITIALIZED_VAR() マクロの導入 — Motohiro KOSAKI <redmine@...>

Feature #3018: UNINITIALIZED_VAR() マクロの導入

12 messages 2010/03/26

[#40805] Improvement of Fiber switching cost with system dependent way — SASADA Koichi <ko1@...>

 ささだです.

10 messages 2010/03/28

[ruby-dev:40801] Re: [Feature #2969] String#to_f が -h.hhh±pd を解釈できるように

From: "NARUSE, Yui" <naruse@...>
Date: 2010-03-28 07:11:48 UTC
List: ruby-dev #40801
(2010/03/27 23:49), Tanaka Akira wrote:
> 2010年3月27日19:14 NARUSE, Yui<[email protected]>:
> 
>> ML 上での最大の use case は浮動小数点数を理解していないユーザへの説明用でしょうね。
> 
> その用途に必要なのは、String#to_f より、まず Float#to_s なんじゃないですかね。
> 
> printf でもいいですが。

理解していないユーザのために、通常の利便性を落とすことは考えませんでした。
なので、printf でいいんじゃないかなぁと思います。
Float#to_s(16) で期待するのがこの形式かというと、また少し悩むところがありますし。

なお、「ML 上での」とつけたのは観測可能だからでした。

個人的な利用でいうと、Math.atanh や Math.log 周りのバグを修正しているときに、
それぞれの環境の Ruby にパッチを当てつつ、%a の出力をにらめっこしていました。
10 進だと 10 進変換が入るので何が起きているかわからないし、
pack だとどこまでが指数部か一目でわからないので、この形式は有用でした。


ついでに missing/vsnprint.f も含めた printf("%a") のパッチ。

diff --git a/LEGAL b/LEGAL
index 991bb4d..c28a0b5 100644
--- a/LEGAL
+++ b/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 <[email protected]>
+   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.
diff --git a/missing/vsnprintf.c b/missing/vsnprintf.c
index 4e19651..acb09c9 100644
--- a/missing/vsnprintf.c
+++ b/missing/vsnprintf.c
@@ -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';
 	}
-	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 @@ 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);
diff --git a/sprintf.c b/sprintf.c
index bec0569..e26b833 100644
--- a/sprintf.c
+++ b/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;
diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb
index 15424d9..f8dbbd5 100644
--- a/test/ruby/test_sprintf.rb
+++ b/test/ruby/test_sprintf.rb
@@ -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
diff --git a/util.c b/util.c
index 9cdb563..88914be 100644
--- a/util.c
+++ b/util.c
@@ -3860,6 +3857,149 @@ ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *ar
     }
 }
 
+/*-
+ * Copyright (c) 2004-2008 David Schultz <[email protected]>
+ * 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
 {

-- 
NARUSE, Yui  <[email protected]>

In This Thread