1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkFloatToDecimal.h" 9 10 #include <cfloat> 11 #include <climits> 12 #include <cmath> 13 14 #include "SkTypes.h" 15 16 // Return pow(10.0, e), optimized for common cases. 17 static double pow10(int e) { 18 switch (e) { 19 case 0: return 1.0; // common cases 20 case 1: return 10.0; 21 case 2: return 100.0; 22 case 3: return 1e+03; 23 case 4: return 1e+04; 24 case 5: return 1e+05; 25 case 6: return 1e+06; 26 case 7: return 1e+07; 27 case 8: return 1e+08; 28 case 9: return 1e+09; 29 case 10: return 1e+10; 30 case 11: return 1e+11; 31 case 12: return 1e+12; 32 case 13: return 1e+13; 33 case 14: return 1e+14; 34 case 15: return 1e+15; 35 default: 36 if (e > 15) { 37 double value = 1e+15; 38 while (e-- > 15) { value *= 10.0; } 39 return value; 40 } else { 41 SkASSERT(e < 0); 42 double value = 1.0; 43 while (e++ < 0) { value /= 10.0; } 44 return value; 45 } 46 } 47 } 48 49 /** Write a string into result, includeing a terminating '\0' (for 50 unit testing). Return strlen(result) (for SkWStream::write) The 51 resulting string will be in the form /[-]?([0-9]*.)?[0-9]+/ and 52 sscanf(result, "%f", &x) will return the original value iff the 53 value is finite. This function accepts all possible input values. 54 55 Motivation: "PDF does not support [numbers] in exponential format 56 (such as 6.02e23)." Otherwise, this function would rely on a 57 sprintf-type function from the standard library. */ 58 unsigned SkFloatToDecimal(float value, char result[kMaximumSkFloatToDecimalLength]) { 59 /* The longest result is -FLT_MIN. 60 We serialize it as "-.0000000000000000000000000000000000000117549435" 61 which has 48 characters plus a terminating '\0'. */ 62 63 static_assert(kMaximumSkFloatToDecimalLength == 49, ""); 64 // 3 = '-', '.', and '\0' characters. 65 // 9 = number of significant digits 66 // abs(FLT_MIN_10_EXP) = number of zeros in FLT_MIN 67 static_assert(kMaximumSkFloatToDecimalLength == 3 + 9 - FLT_MIN_10_EXP, ""); 68 69 /* section C.1 of the PDF1.4 spec (http://goo.gl/0SCswJ) says that 70 most PDF rasterizers will use fixed-point scalars that lack the 71 dynamic range of floats. Even if this is the case, I want to 72 serialize these (uncommon) very small and very large scalar 73 values with enough precision to allow a floating-point 74 rasterizer to read them in with perfect accuracy. 75 Experimentally, rasterizers such as pdfium do seem to benefit 76 from this. Rasterizers that rely on fixed-point scalars should 77 gracefully ignore these values that they can not parse. */ 78 char* output = &result[0]; 79 const char* const end = &result[kMaximumSkFloatToDecimalLength - 1]; 80 // subtract one to leave space for '\0'. 81 82 /* This function is written to accept any possible input value, 83 including non-finite values such as INF and NAN. In that case, 84 we ignore value-correctness and and output a syntacticly-valid 85 number. */ 86 if (value == INFINITY) { 87 value = FLT_MAX; // nearest finite float. 88 } 89 if (value == -INFINITY) { 90 value = -FLT_MAX; // nearest finite float. 91 } 92 if (!std::isfinite(value) || value == 0.0f) { 93 // NAN is unsupported in PDF. Always output a valid number. 94 // Also catch zero here, as a special case. 95 *output++ = '0'; 96 *output = '\0'; 97 return static_cast<unsigned>(output - result); 98 } 99 if (value < 0.0) { 100 *output++ = '-'; 101 value = -value; 102 } 103 SkASSERT(value >= 0.0f); 104 105 int binaryExponent; 106 (void)std::frexp(value, &binaryExponent); 107 static const double kLog2 = 0.3010299956639812; // log10(2.0); 108 int decimalExponent = static_cast<int>(std::floor(kLog2 * binaryExponent)); 109 int decimalShift = decimalExponent - 8; 110 double power = pow10(-decimalShift); 111 SkASSERT(value * power <= (double)INT_MAX); 112 int d = static_cast<int>(value * power + 0.5); 113 // SkASSERT(value == (float)(d * pow(10.0, decimalShift))); 114 SkASSERT(d <= 999999999); 115 if (d > 167772159) { // floor(pow(10,1+log10(1<<24))) 116 // need one fewer decimal digits for 24-bit precision. 117 decimalShift = decimalExponent - 7; 118 // SkASSERT(power * 0.1 = pow10(-decimalShift)); 119 // recalculate to get rounding right. 120 d = static_cast<int>(value * (power * 0.1) + 0.5); 121 SkASSERT(d <= 99999999); 122 } 123 while (d % 10 == 0) { 124 d /= 10; 125 ++decimalShift; 126 } 127 SkASSERT(d > 0); 128 // SkASSERT(value == (float)(d * pow(10.0, decimalShift))); 129 unsigned char buffer[9]; // decimal value buffer. 130 int bufferIndex = 0; 131 do { 132 buffer[bufferIndex++] = d % 10; 133 d /= 10; 134 } while (d != 0); 135 SkASSERT(bufferIndex <= (int)sizeof(buffer) && bufferIndex > 0); 136 if (decimalShift >= 0) { 137 do { 138 --bufferIndex; 139 *output++ = '0' + buffer[bufferIndex]; 140 } while (bufferIndex); 141 for (int i = 0; i < decimalShift; ++i) { 142 *output++ = '0'; 143 } 144 } else { 145 int placesBeforeDecimal = bufferIndex + decimalShift; 146 if (placesBeforeDecimal > 0) { 147 while (placesBeforeDecimal-- > 0) { 148 --bufferIndex; 149 *output++ = '0' + buffer[bufferIndex]; 150 } 151 *output++ = '.'; 152 } else { 153 *output++ = '.'; 154 int placesAfterDecimal = -placesBeforeDecimal; 155 while (placesAfterDecimal-- > 0) { 156 *output++ = '0'; 157 } 158 } 159 while (bufferIndex > 0) { 160 --bufferIndex; 161 *output++ = '0' + buffer[bufferIndex]; 162 if (output == end) { 163 break; // denormalized: don't need extra precision. 164 // Note: denormalized numbers will not have the same number of 165 // significantDigits, but do not need them to round-trip. 166 } 167 } 168 } 169 SkASSERT(output <= end); 170 *output = '\0'; 171 return static_cast<unsigned>(output - result); 172 } 173