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