OLD | NEW |
(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 "double.h" |
| 10 #include "grisu3.h" |
| 11 |
| 12 using namespace v8::internal; |
| 13 |
| 14 static const int kBufferSize = 50; |
| 15 |
| 16 TEST(DoubleExtremes) { |
| 17 char buffer[kBufferSize]; |
| 18 int length; |
| 19 int point; |
| 20 int sign; |
| 21 bool status; |
| 22 double min_double = 5e-324; |
| 23 status = grisu3(min_double, buffer, &sign, &length, &point); |
| 24 CHECK(status); |
| 25 CHECK_EQ("5", buffer); |
| 26 CHECK_EQ(-323, point); |
| 27 |
| 28 double max_double = 1.7976931348623157e308; |
| 29 status = grisu3(max_double, buffer, &sign, &length, &point); |
| 30 CHECK(status); |
| 31 CHECK_EQ("17976931348623157", buffer); |
| 32 CHECK_EQ(309, point); |
| 33 } |
| 34 |
| 35 |
| 36 static long double MyFabsL(long double d) { |
| 37 if (d < 0.0) |
| 38 return -d; |
| 39 else |
| 40 return d; |
| 41 } |
| 42 |
| 43 |
| 44 |
| 45 static bool IsCorrect(double v, char* buffer, int sign, int length, int k) { |
| 46 // First test if the result is correct |
| 47 return v == sign * atof(buffer); |
| 48 } |
| 49 |
| 50 |
| 51 static bool IsRounded(double v, char* buffer, int sign, int length, int k) { |
| 52 long double lv = v; |
| 53 long double lbuffer; |
| 54 sscanf(buffer, "%Lf", &lbuffer); |
| 55 lbuffer *= sign; |
| 56 if (buffer[length-1] != '1') { |
| 57 long double lower; |
| 58 buffer[length-1]--; |
| 59 if (v == sign * atof(buffer)) { |
| 60 // The lower buffer is a possible solution too. Let's see if it is closer. |
| 61 sscanf(buffer, "%Lf", &lower); |
| 62 lower *= sign; |
| 63 if (MyFabsL(lv-lower) < MyFabsL(lv-lbuffer)) |
| 64 return false; |
| 65 } |
| 66 buffer[length-1]++; |
| 67 } |
| 68 if (buffer[length-1] != '9') { |
| 69 long double bigger; |
| 70 buffer[length-1]++; |
| 71 if (v == sign*atof(buffer)) { |
| 72 sscanf(buffer, "%Lf", &bigger); |
| 73 bigger *= sign; |
| 74 if (MyFabsL(lv-bigger) < MyFabsL(lv-lbuffer)) |
| 75 return false; |
| 76 } |
| 77 buffer[length-1]--; |
| 78 } |
| 79 return true; |
| 80 } |
| 81 |
| 82 |
| 83 static bool IsShortest(double v, char* buffer, int sign, int length, int k) { |
| 84 // Now test if a shorter version would still yield the same result. |
| 85 // Not an exhaustive test, but better than nothing. |
| 86 buffer[length-1] = 'e'; |
| 87 snprintf(&buffer[length], kBufferSize - length - 1, "%d", k+1); |
| 88 if (v == sign * atof(buffer)) return false; |
| 89 if (buffer[length-2] != '9') { |
| 90 buffer[length-2]++; |
| 91 snprintf(&buffer[length], kBufferSize - length - 1, "%d", k+1); |
| 92 if (v == sign * atof(buffer)) return false; |
| 93 } |
| 94 return true; |
| 95 } |
| 96 |
| 97 |
| 98 TEST(VariousDoubles) { |
| 99 char buffer[kBufferSize]; |
| 100 int length; |
| 101 int point; |
| 102 int sign; |
| 103 int status; |
| 104 status = grisu3(4294967272.0, buffer, &sign, &length, &point); |
| 105 CHECK(status); |
| 106 CHECK_EQ("4294967272", buffer); |
| 107 CHECK_EQ(10, point); |
| 108 |
| 109 status = grisu3(4.1855804968213567e298, buffer, &sign, &length, &point); |
| 110 CHECK(status); |
| 111 CHECK_EQ("4185580496821357", buffer); |
| 112 CHECK_EQ(299, point); |
| 113 |
| 114 status = grisu3(5.5626846462680035e-309, buffer, &sign, &length, &point); |
| 115 CHECK(status); |
| 116 CHECK_EQ("5562684646268003", buffer); |
| 117 CHECK_EQ(-308, point); |
| 118 |
| 119 status = grisu3(-2147483648.0, buffer, &sign, &length, &point); |
| 120 CHECK(status); |
| 121 CHECK_EQ(1, sign); |
| 122 CHECK_EQ("2147483648", buffer); |
| 123 CHECK_EQ(10, point); |
| 124 |
| 125 status = grisu3(-3.5844466002796428e+298, buffer, &sign, &length, &point); |
| 126 if (status) { // Not all grisu3 variants manage to compute this number. |
| 127 CHECK_EQ(1, sign); |
| 128 CHECK_EQ("35844466002796428", buffer); |
| 129 CHECK_EQ(299, point); |
| 130 } |
| 131 |
| 132 uint64_t smallest_normal64 = V8_2PART_UINT64_C(0x00100000,00000000); |
| 133 double v = Double(smallest_normal64).value(); |
| 134 status = grisu3(v, buffer, &sign, &length, &point); |
| 135 if (sign == 0) { |
| 136 sign = 1; |
| 137 } else { |
| 138 sign = -1; |
| 139 } |
| 140 if (status) { |
| 141 int k = point - length; |
| 142 // Integrate exponent into buffer. |
| 143 buffer[length] = 'e'; |
| 144 snprintf(&buffer[length+1], kBufferSize - length - 1, "%d", k); |
| 145 CHECK(IsCorrect(v, buffer, sign, length, k)); |
| 146 CHECK(IsRounded(v, buffer, sign, length, k)); |
| 147 CHECK(IsShortest(v, buffer, sign, length, k)); |
| 148 } |
| 149 |
| 150 uint64_t largest_denormal64 = V8_2PART_UINT64_C(0x000FFFFF,FFFFFFFF); |
| 151 v = Double(largest_denormal64).value(); |
| 152 status = grisu3(v, buffer, &sign, &length, &point); |
| 153 if (sign == 0) { |
| 154 sign = 1; |
| 155 } else { |
| 156 sign = -1; |
| 157 } |
| 158 if (status) { |
| 159 int k = point - length; |
| 160 // Integrate exponent into buffer. |
| 161 buffer[length] = 'e'; |
| 162 snprintf(&buffer[length+1], kBufferSize - length - 1, "%d", k); |
| 163 CHECK(IsCorrect(v, buffer, sign, length, k)); |
| 164 CHECK(IsRounded(v, buffer, sign, length, k)); |
| 165 CHECK(IsShortest(v, buffer, sign, length, k)); |
| 166 } |
| 167 } |
| 168 |
| 169 |
| 170 static double random_double() { |
| 171 uint64_t double64 = 0; |
| 172 for (int i = 0; i < 8; i++) { |
| 173 double64 <<= 8; |
| 174 double64 += rand() % 256; |
| 175 } |
| 176 return Double(double64).value(); |
| 177 } |
| 178 |
| 179 |
| 180 TEST(RandomDoubles) { |
| 181 // For a more thorough testing increase the iteration count. |
| 182 // We also check kGrisu3MaximalLength in here. |
| 183 const int kIterationCount = 100000; |
| 184 int succeeded = 0; |
| 185 int total = 0; |
| 186 char buffer[kBufferSize]; |
| 187 int length; |
| 188 int point; |
| 189 int sign; |
| 190 bool needed_max_length = false; |
| 191 |
| 192 for (int i = 0; i < kIterationCount; ++i) { |
| 193 double v = random_double(); |
| 194 if (v != v) continue; // NaN |
| 195 if (v == 0.0) continue; |
| 196 total++; |
| 197 int status = grisu3(v, buffer, &sign, &length, &point); |
| 198 CHECK_GE(kGrisu3MaximalLength, length); |
| 199 if (length == kGrisu3MaximalLength) needed_max_length = true; |
| 200 if (sign == 0) { |
| 201 sign = 1; |
| 202 } else { |
| 203 sign = -1; |
| 204 } |
| 205 if (!status) continue; |
| 206 succeeded++; |
| 207 int k = point - length; |
| 208 // Integrate exponent into buffer. |
| 209 buffer[length] = 'e'; |
| 210 snprintf(&buffer[length+1], kBufferSize - length - 1, "%d", k); |
| 211 CHECK(IsCorrect(v, buffer, sign, length, k)); |
| 212 CHECK(IsRounded(v, buffer, sign, length, k)); |
| 213 CHECK(IsShortest(v, buffer, sign, length, k)); |
| 214 } |
| 215 CHECK_GT(succeeded*1.0/total, 0.99); |
| 216 CHECK(needed_max_length); |
| 217 } |
OLD | NEW |