-
Notifications
You must be signed in to change notification settings - Fork 247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix decimal decoding #401
Fix decimal decoding #401
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
|
||
package com.pingcap.tikv.codec; | ||
|
||
import com.google.common.annotations.VisibleForTesting; | ||
import java.math.BigDecimal; | ||
import java.util.Arrays; | ||
|
||
|
@@ -58,12 +59,12 @@ public class MyDecimal { | |
/* | ||
* Returns total precision of this decimal. Basically, it is sum of digitsInt and digitsFrac. But there | ||
* are some special cases need to be token care of such as 000.001. | ||
* Precision reflects the actual effective precision without leading zero | ||
*/ | ||
public int precision() { | ||
int frac = this.digitsFrac; | ||
int digitsInt = | ||
this.removeLeadingZeros()[ | ||
1]; /*this function return an array and the second element is digitsInt*/ | ||
this.removeLeadingZeros()[1]; /*this function return an array and the second element is digitsInt*/ | ||
int precision = digitsInt + frac; | ||
// if no precision, it is just 0. | ||
if (precision == 0) { | ||
|
@@ -72,7 +73,10 @@ public int precision() { | |
return precision; | ||
} | ||
|
||
/** Returns fraction digits that counts how many digits after ".". */ | ||
/** | ||
* Returns fraction digits that counts how many digits after ".". | ||
* frac() reflects the actual effective fraction without trailing zero | ||
*/ | ||
public int frac() { | ||
return digitsFrac; | ||
} | ||
|
@@ -92,8 +96,7 @@ public void fromDecimal(double value) { | |
* | ||
* @param precision precision specifies total digits that this decimal will be.. | ||
* @param frac frac specifies how many fraction digits | ||
* @param bin bin is binary string which represents a decimal value. TODO: (zhexuany) overflow and | ||
* truncated exception need to be done later. | ||
* @param bin bin is binary string which represents a decimal value. | ||
*/ | ||
public int fromBin(int precision, int frac, int[] bin) { | ||
if (bin.length == 0) { | ||
|
@@ -134,13 +137,13 @@ public int fromBin(int precision, int frac, int[] bin) { | |
wordsIntTo = wordBufLen; | ||
wordsFracTo = 0; | ||
overflow = true; | ||
} else { | ||
wordsIntTo = wordsInt; | ||
wordsFracTo = wordBufLen - wordsInt; | ||
truncated = true; | ||
} | ||
wordsIntTo = wordsInt; | ||
wordsFracTo = wordBufLen - wordsInt; | ||
truncated = true; | ||
} | ||
wordsIntTo = wordsInt; | ||
wordsFracTo = wordsFrac; | ||
|
||
if (overflow || truncated) { | ||
if (wordsIntTo < oldWordsIntTo) { | ||
binIdx += dig2bytes[leadingDigits] + (wordsInt - wordsIntTo) * wordSize; | ||
|
@@ -151,8 +154,8 @@ public int fromBin(int precision, int frac, int[] bin) { | |
} | ||
|
||
this.negative = mask != 0; | ||
this.digitsInt = wordsInt * digitsPerWord + leadingDigits; | ||
this.digitsFrac = wordsFrac * digitsPerWord + trailingDigits; | ||
this.digitsInt = (byte)(wordsInt * digitsPerWord + leadingDigits); | ||
this.digitsFrac = (byte)(wordsFrac * digitsPerWord + trailingDigits); | ||
|
||
int wordIdx = 0; | ||
if (leadingDigits > 0) { | ||
|
@@ -264,25 +267,26 @@ private int digitsToWords(int digits) { | |
/** | ||
* Reads a word from a array at given size. | ||
* | ||
* @param b b is source data. | ||
* @param b b is source data of unsigned byte as int[] | ||
* @param size is word size which can be used in switch statement. | ||
* @param start start indicates the where start to read. | ||
*/ | ||
private int readWord(int[] b, int size, int start) { | ||
@VisibleForTesting | ||
public static int readWord(int[] b, int size, int start) { | ||
int x = 0; | ||
switch (size) { | ||
case 1: | ||
x = b[start]; | ||
x = (byte)b[start]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same reason. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In java byte is signed. b[start] is unsigned in fact since we read as unsigned byte. |
||
break; | ||
case 2: | ||
x = (b[start] << 8) + b[start + 1]; | ||
x = (((byte)b[start]) << 8) + (b[start + 1] & 0xFF); | ||
break; | ||
case 3: | ||
int sign = b[start] & 128; | ||
if (sign > 0) { | ||
x = 255 << 24 | (b[start] & 0xFF) << 16 | (b[start + 1] & 0xFF) << 8 | (b[start + 2]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a reminder: b's type is byte[] which shares a range from -128 to 127 whereas golang's byte shares range from 0 to 255. We are better take There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Additionally, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. my bad, java does not have uint.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ~(0x7F << 24 | b[start] << 16 | b[start + 1] << 8 | (b[start + 2]) + 1); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you may use ~(((b[start] & 7FFF) << 16 | (b[start + 1] & 0xFF) << 8 | (b[start + 2] & 0xFF)) + 1); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 255 << 24 has correct binary form. Numeric overflow does not affect binary. ignore my comment. |
||
x = 0xFF << 24 | (b[start] << 16) | (b[start + 1] << 8) | (b[start + 2]); | ||
} else { | ||
x = b[start] << 16 | b[start + 1] << 8 | b[start + 2]; | ||
x = b[start] << 16 | (b[start + 1] << 8) | b[start + 2]; | ||
} | ||
break; | ||
case 4: | ||
|
@@ -292,6 +296,12 @@ private int readWord(int[] b, int size, int start) { | |
return x; | ||
} | ||
|
||
public static void main(String args[]) { | ||
int[] b = new int[]{250,250,250}; | ||
int x = 255 << 24 | (b[0] << 16) | (b[0 + 1] << 8) | (b[0 + 2]); | ||
System.out.println(x); | ||
} | ||
|
||
/** | ||
* parser a decimal value from a string. | ||
* | ||
|
@@ -320,7 +330,7 @@ private void fromCharArray(char[] str) { | |
// [-, 1, 2, 3] | ||
// [+, 1, 2, 3] | ||
// for +/-, we need skip them and record sign information into negative field. | ||
switch (str[0]) { | ||
switch (str[startIdx]) { | ||
case '-': | ||
this.negative = true; | ||
startIdx++; | ||
|
@@ -335,8 +345,8 @@ private void fromCharArray(char[] str) { | |
} | ||
// we initialize strIdx in case of sign notation, here we need substract startIdx from strIdx casue strIdx is used for counting the number of digits. | ||
int digitsInt = strIdx - startIdx; | ||
int digitsFrac = 0; | ||
int endIdx = 0; | ||
int digitsFrac; | ||
int endIdx; | ||
if (strIdx < str.length && str[strIdx] == '.') { | ||
endIdx = strIdx + 1; | ||
// detect where is the end index of this char array. | ||
|
@@ -363,13 +373,12 @@ private void fromCharArray(char[] str) { | |
wordsInt = wordBufLen; | ||
wordsFrac = 0; | ||
overflow = true; | ||
} else { | ||
wordsFrac = wordBufLen - wordsInt; | ||
truncated = true; | ||
} | ||
// wordsIntTo = wordsInt; | ||
wordsFrac = wordBufLen - wordsInt; | ||
truncated = true; | ||
|
||
} | ||
// wordsIntTo = wordsInt; | ||
// wordsFracTo = wordsFrac; | ||
|
||
if (overflow || truncated) { | ||
digitsFrac = wordsFrac * digitsPerWord; | ||
|
@@ -700,7 +709,6 @@ public int[] toBin(int precision, int frac) { | |
int originFracSize = fracSize; | ||
int[] bin = new int[intSize + fracSize]; | ||
int binIdx = 0; | ||
//TODO, overflow and truncated later | ||
int[] res = this.removeLeadingZeros(); | ||
int wordIdxFrom = res[0]; | ||
int digitsIntFrom = res[1]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type conversion seems unnecessary. Digits of int and fraction can never go beyond 127. tidb does this simply because it is static type language. It has to do such conversion otherwise compiler will not be happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To keep the same behavior as in TiDB which does a cap.