Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Side by Side Diff: test/cctest/test-grisu3.cc

Issue 619005: Fast algorithm for double->string conversion. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2
3 #include <stdlib.h>
4
5 #include "v8.h"
6
7 #include "platform.h"
8 #include "cctest.h"
9 #include "diy_fp.h"
10 #include "double.h"
11 #include "grisu3.h"
12
13 using namespace v8::internal;
14
15 static const int kBufferSize = 50;
16
17 TEST(DoubleExtremes) {
18 char buffer[kBufferSize];
19 int length;
20 int point;
21 int sign;
22 bool status;
23 double min_double = 5e-324;
24 status = grisu3(min_double, buffer, &sign, &length, &point);
25 CHECK(status);
26 CHECK_EQ("5", buffer);
27 CHECK_EQ(-323, point);
28
29 double max_double = 1.7976931348623157e308;
30 status = grisu3(max_double, buffer, &sign, &length, &point);
31 CHECK(status);
32 CHECK_EQ("17976931348623157", buffer);
33 CHECK_EQ(309, point);
34 }
35
36
37 static long double MyFabsL(long double d) {
38 if (d < 0.0)
39 return -d;
40 else
41 return d;
42 }
43
44
45 static long double ComposeDouble(
46 char* buffer, int sign, int length, int point) {
47 int k = point - length;
48 // Integrate exponent into buffer.
49 buffer[length] = 'e';
50 snprintf(&buffer[length+1], kBufferSize - length - 1, "%d", k);
51 long double result;
52 sscanf(buffer, "%Lf", &result); // NOLINT
53 if (sign) {
54 result *= -1;
55 }
56 return result;
57 }
58
59
60 static bool IsCorrect(double v, char* buffer, int sign, int length, int point) {
61 return v == static_cast<double>(ComposeDouble(buffer, sign, length, point));
62 }
63
64 // IsRounded relies on the precision of long doubles. There might be false
65 // positives and negatives.
66 static bool IsRounded(double v, char* buffer, int sign, int length, int point) {
67 long double lv = v;
68 long double lbuffer;
69 long double unit;
70 char temp_buffer[20];
71 int k = point - length;
72 int i = 0;
73
74 temp_buffer[i++] = '1';
75 unit = ComposeDouble(temp_buffer, 0, 1, 1 + k);
76 lbuffer = ComposeDouble(buffer, sign, length, point);
77 return MyFabsL(2 * (lbuffer - lv)) < unit;
78 }
79
80
81 static bool IsShortest(
82 double v, char* buffer, int sign, int length, int point) {
83 // Now test if a shorter version would still yield the same result.
84 // Not an exhaustive test, but better than nothing.
85
86 if (length == 1) return true;
87
88 char last_digit = buffer[length - 1];
89
90 if (buffer[length - 1] == '0') return false;
91
92 if (v == static_cast<double>(ComposeDouble(buffer, sign, length - 1, point)))
93 return false;
94
95 if (buffer[length-2] != '9') {
96 buffer[length - 2]++;
97 if (v == static_cast<double>(ComposeDouble(buffer, sign, length-1, point)))
98 return false;
99 buffer[length - 2]--;
100 }
101 buffer[length - 1] = last_digit;
102 return true;
103 }
104
105
106 TEST(DoubleTestFunctions) {
107 char buffer[kBufferSize];
108
109 strncpy(buffer, "12345", kBufferSize);
110 CHECK(IsCorrect(123.45, buffer, 0, 5, 3));
111 strncpy(buffer, "12345", kBufferSize);
112 CHECK(IsCorrect(1.2345, buffer, 0, 5, 1));
113 strncpy(buffer, "12345", kBufferSize);
114 CHECK(!IsCorrect(1.2344, buffer, 0, 5, 1));
115 strncpy(buffer, "12345", kBufferSize);
116 CHECK(!IsCorrect(1.2345, buffer, 0, 5, 2));
117 strncpy(buffer, "12345", kBufferSize);
118 CHECK(!IsCorrect(1.2345, buffer, 0, 4, 1));
119
120 strncpy(buffer, "1234", kBufferSize);
121 CHECK(IsRounded(123.44, buffer, 0, 4, 3));
122 strncpy(buffer, "1234", kBufferSize);
123 CHECK(!IsRounded(123.4500000000001, buffer, 0, 4, 3));
124 strncpy(buffer, "1234", kBufferSize);
125 CHECK(IsRounded(123.44999999, buffer, 0, 4, 3));
126 strncpy(buffer, "1234", kBufferSize);
127 CHECK(IsRounded(123.44999999, buffer, 0, 3, 3));
128
129 strncpy(buffer, "1234567000000000000000000001", kBufferSize);
130 CHECK(IsShortest(123.45, buffer, 0, 5, 3));
131 strncpy(buffer, "1234567000000000000000000001", kBufferSize);
132 CHECK(IsShortest(123.4567, buffer, 0, 7, 3));
133 strncpy(buffer, "1234567000000000000000000001", kBufferSize);
134 CHECK(!IsShortest(123.4567, buffer, 0, strlen(buffer), 3));
135
136 strncpy(buffer, "123456699999999999999999999999999999", kBufferSize);
137 CHECK(!IsShortest(123.4567, buffer, 0, strlen(buffer), 3));
138 strncpy(buffer, "123456699999999999999999999999999999", kBufferSize);
139 CHECK(IsShortest(123.456, buffer, 0, 6, 3));
140 }
141
142
143 TEST(VariousDoubles) {
144 char buffer[kBufferSize];
145 int length;
146 int point;
147 int sign;
148 int status;
149 status = grisu3(4294967272.0, buffer, &sign, &length, &point);
150 CHECK(status);
151 CHECK_EQ("4294967272", buffer);
152 CHECK_EQ(10, point);
153
154 status = grisu3(4.1855804968213567e298, buffer, &sign, &length, &point);
155 CHECK(status);
156 CHECK_EQ("4185580496821357", buffer);
157 CHECK_EQ(299, point);
158
159 status = grisu3(5.5626846462680035e-309, buffer, &sign, &length, &point);
160 CHECK(status);
161 CHECK_EQ("5562684646268003", buffer);
162 CHECK_EQ(-308, point);
163
164 status = grisu3(-2147483648.0, buffer, &sign, &length, &point);
165 CHECK(status);
166 CHECK_EQ(1, sign);
167 CHECK_EQ("2147483648", buffer);
168 CHECK_EQ(10, point);
169
170 status = grisu3(-3.5844466002796428e+298, buffer, &sign, &length, &point);
171 if (status) { // Not all grisu3 variants manage to compute this number.
172 CHECK_EQ(1, sign);
173 CHECK_EQ("35844466002796428", buffer);
174 CHECK_EQ(299, point);
175 }
176
177 uint64_t smallest_normal64 = V8_2PART_UINT64_C(0x00100000, 00000000);
178 double v = Double(smallest_normal64).value();
179 status = grisu3(v, buffer, &sign, &length, &point);
180 if (status) {
181 CHECK(IsCorrect(v, buffer, sign, length, point));
182 CHECK(IsRounded(v, buffer, sign, length, point));
183 CHECK(IsShortest(v, buffer, sign, length, point));
184 }
185
186 uint64_t largest_denormal64 = V8_2PART_UINT64_C(0x000FFFFF, FFFFFFFF);
187 v = Double(largest_denormal64).value();
188 status = grisu3(v, buffer, &sign, &length, &point);
189 if (status) {
190 CHECK(IsCorrect(v, buffer, sign, length, point));
191 CHECK(IsRounded(v, buffer, sign, length, point));
192 CHECK(IsShortest(v, buffer, sign, length, point));
193 }
194 }
195
196
197 static double random_double() {
198 uint64_t double64 = 0;
199 for (int i = 0; i < 8; i++) {
200 double64 <<= 8;
201 double64 += rand() % 256; // NOLINT
202 }
203 return Double(double64).value();
204 }
205
206
207 TEST(RandomDoubles) {
208 // For a more thorough testing increase the iteration count.
209 // We also check kGrisu3MaximalLength in here.
210 const int kIterationCount = 100000;
211 int succeeded = 0;
212 int total = 0;
213 char buffer[kBufferSize];
214 int length;
215 int point;
216 int sign;
217 bool needed_max_length = false;
218
219 for (int i = 0; i < kIterationCount; ++i) {
220 double v = random_double();
221 if (v != v) continue; // NaN
222 if (v == 0.0) continue;
223 total++;
224 int status = grisu3(v, buffer, &sign, &length, &point);
225 CHECK_GE(kGrisu3MaximalLength, length);
226 if (length == kGrisu3MaximalLength) needed_max_length = true;
227 if (!status) continue;
228 succeeded++;
229 CHECK(IsCorrect(v, buffer, sign, length, point));
230 CHECK(IsRounded(v, buffer, sign, length, point));
231 CHECK(IsShortest(v, buffer, sign, length, point));
232 }
233 CHECK_GT(succeeded*1.0/total, 0.99);
234 CHECK(needed_max_length);
235 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698