1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #define LOG_TAG "RealToString" 19 20 #include <string.h> 21 #include <math.h> 22 #include <stdlib.h> 23 24 #include "JNIHelp.h" 25 #include "JniConstants.h" 26 #include "ScopedPrimitiveArray.h" 27 #include "cbigint.h" 28 29 #define INV_LOG_OF_TEN_BASE_2 (0.30102999566398114) /* Local */ 30 31 /*NB the Number converter methods are synchronized so it is possible to 32 *have global data for use by bigIntDigitGenerator */ 33 #define RM_SIZE 21 /* Local. */ 34 #define STemp_SIZE 22 /* Local. */ 35 36 /* The algorithm for this particular function can be found in: 37 * 38 * Printing Floating-Point Numbers Quickly and Accurately, Robert 39 * G. Burger, and R. Kent Dybvig, Programming Language Design and 40 * Implementation (PLDI) 1996, pp.108-116. 41 * 42 * The previous implementation of this function combined m+ and m- into 43 * one single M which caused some inaccuracy of the last digit. The 44 * particular case below shows this inaccuracy: 45 * 46 * System.out.println(new Double((1.234123412431233E107)).toString()); 47 * System.out.println(new Double((1.2341234124312331E107)).toString()); 48 * System.out.println(new Double((1.2341234124312332E107)).toString()); 49 * 50 * outputs the following: 51 * 52 * 1.234123412431233E107 53 * 1.234123412431233E107 54 * 1.234123412431233E107 55 * 56 * instead of: 57 * 58 * 1.234123412431233E107 59 * 1.2341234124312331E107 60 * 1.2341234124312331E107 61 * 62 */ 63 void RealToString_bigIntDigitGenerator(JNIEnv* env, jobject obj, jlong f, jint e, 64 jboolean isDenormalized, jint p) { 65 int RLength, SLength, TempLength, mplus_Length, mminus_Length; 66 int high, low, i; 67 jint k, firstK, U; 68 69 uint64_t R[RM_SIZE], S[STemp_SIZE], mplus[RM_SIZE], mminus[RM_SIZE], Temp[STemp_SIZE]; 70 71 memset (R , 0, RM_SIZE * sizeof (uint64_t)); 72 memset (S , 0, STemp_SIZE * sizeof (uint64_t)); 73 memset (mplus , 0, RM_SIZE * sizeof (uint64_t)); 74 memset (mminus, 0, RM_SIZE * sizeof (uint64_t)); 75 memset (Temp , 0, STemp_SIZE * sizeof (uint64_t)); 76 77 if (e >= 0) 78 { 79 *R = f; 80 *mplus = *mminus = 1; 81 simpleShiftLeftHighPrecision (mminus, RM_SIZE, e); 82 if (f != (2 << (p - 1))) 83 { 84 simpleShiftLeftHighPrecision (R, RM_SIZE, e + 1); 85 *S = 2; 86 /* 87 * m+ = m+ << e results in 1.0e23 to be printed as 88 * 0.9999999999999999E23 89 * m+ = m+ << e+1 results in 1.0e23 to be printed as 90 * 1.0e23 (caused too much rounding) 91 * 470fffffffffffff = 2.0769187434139308E34 92 * 4710000000000000 = 2.076918743413931E34 93 */ 94 simpleShiftLeftHighPrecision (mplus, RM_SIZE, e); 95 } 96 else 97 { 98 simpleShiftLeftHighPrecision (R, RM_SIZE, e + 2); 99 *S = 4; 100 simpleShiftLeftHighPrecision (mplus, RM_SIZE, e + 1); 101 } 102 } 103 else 104 { 105 if (isDenormalized || (f != (2 << (p - 1)))) 106 { 107 *R = f << 1; 108 *S = 1; 109 simpleShiftLeftHighPrecision (S, STemp_SIZE, 1 - e); 110 *mplus = *mminus = 1; 111 } 112 else 113 { 114 *R = f << 2; 115 *S = 1; 116 simpleShiftLeftHighPrecision (S, STemp_SIZE, 2 - e); 117 *mplus = 2; 118 *mminus = 1; 119 } 120 } 121 122 k = static_cast<int>(ceil ((e + p - 1) * INV_LOG_OF_TEN_BASE_2 - 1e-10)); 123 124 if (k > 0) 125 { 126 timesTenToTheEHighPrecision (S, STemp_SIZE, k); 127 } 128 else 129 { 130 timesTenToTheEHighPrecision (R , RM_SIZE, -k); 131 timesTenToTheEHighPrecision (mplus , RM_SIZE, -k); 132 timesTenToTheEHighPrecision (mminus, RM_SIZE, -k); 133 } 134 135 RLength = mplus_Length = mminus_Length = RM_SIZE; 136 SLength = TempLength = STemp_SIZE; 137 138 memset (Temp + RM_SIZE, 0, (STemp_SIZE - RM_SIZE) * sizeof (uint64_t)); 139 memcpy (Temp, R, RM_SIZE * sizeof (uint64_t)); 140 141 while (RLength > 1 && R[RLength - 1] == 0) 142 --RLength; 143 while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0) 144 --mplus_Length; 145 while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0) 146 --mminus_Length; 147 while (SLength > 1 && S[SLength - 1] == 0) 148 --SLength; 149 TempLength = (RLength > mplus_Length ? RLength : mplus_Length) + 1; 150 addHighPrecision (Temp, TempLength, mplus, mplus_Length); 151 152 if (compareHighPrecision (Temp, TempLength, S, SLength) >= 0) 153 { 154 firstK = k; 155 } 156 else 157 { 158 firstK = k - 1; 159 simpleAppendDecimalDigitHighPrecision (R , ++RLength , 0); 160 simpleAppendDecimalDigitHighPrecision (mplus , ++mplus_Length , 0); 161 simpleAppendDecimalDigitHighPrecision (mminus, ++mminus_Length, 0); 162 while (RLength > 1 && R[RLength - 1] == 0) 163 --RLength; 164 while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0) 165 --mplus_Length; 166 while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0) 167 --mminus_Length; 168 } 169 170 static jfieldID digitsFid = env->GetFieldID(JniConstants::realToStringClass, "digits", "[I"); 171 jintArray javaDigits = reinterpret_cast<jintArray>(env->GetObjectField(obj, digitsFid)); 172 ScopedIntArrayRW digits(env, javaDigits); 173 if (digits.get() == NULL) { 174 return; 175 } 176 177 jint digitCount = 0; 178 do 179 { 180 U = 0; 181 for (i = 3; i >= 0; --i) 182 { 183 TempLength = SLength + 1; 184 Temp[SLength] = 0; 185 memcpy (Temp, S, SLength * sizeof (uint64_t)); 186 simpleShiftLeftHighPrecision (Temp, TempLength, i); 187 if (compareHighPrecision (R, RLength, Temp, TempLength) >= 0) 188 { 189 subtractHighPrecision (R, RLength, Temp, TempLength); 190 U += 1 << i; 191 } 192 } 193 194 low = compareHighPrecision (R, RLength, mminus, mminus_Length) <= 0; 195 196 memset (Temp + RLength, 0, (STemp_SIZE - RLength) * sizeof (uint64_t)); 197 memcpy (Temp, R, RLength * sizeof (uint64_t)); 198 TempLength = (RLength > mplus_Length ? RLength : mplus_Length) + 1; 199 addHighPrecision (Temp, TempLength, mplus, mplus_Length); 200 201 high = compareHighPrecision (Temp, TempLength, S, SLength) >= 0; 202 203 if (low || high) 204 break; 205 206 simpleAppendDecimalDigitHighPrecision (R , ++RLength , 0); 207 simpleAppendDecimalDigitHighPrecision (mplus , ++mplus_Length , 0); 208 simpleAppendDecimalDigitHighPrecision (mminus, ++mminus_Length, 0); 209 while (RLength > 1 && R[RLength - 1] == 0) 210 --RLength; 211 while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0) 212 --mplus_Length; 213 while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0) 214 --mminus_Length; 215 digits[digitCount++] = U; 216 } 217 while (1); 218 219 simpleShiftLeftHighPrecision (R, ++RLength, 1); 220 if (low && !high) 221 digits[digitCount++] = U; 222 else if (high && !low) 223 digits[digitCount++] = U + 1; 224 else if (compareHighPrecision (R, RLength, S, SLength) < 0) 225 digits[digitCount++] = U; 226 else 227 digits[digitCount++] = U + 1; 228 229 static jfieldID digitCountFid = env->GetFieldID(JniConstants::realToStringClass, "digitCount", "I"); 230 env->SetIntField(obj, digitCountFid, digitCount); 231 232 static jfieldID firstKFid = env->GetFieldID(JniConstants::realToStringClass, "firstK", "I"); 233 env->SetIntField(obj, firstKFid, firstK); 234 } 235 236 static JNINativeMethod gMethods[] = { 237 NATIVE_METHOD(RealToString, bigIntDigitGenerator, "(JIZI)V"), 238 }; 239 int register_java_lang_RealToString(JNIEnv* env) { 240 return jniRegisterNativeMethods(env, "java/lang/RealToString", gMethods, NELEM(gMethods)); 241 } 242