我正在尝试将float转换为带包装的十进制数,但我发现最接近的解决方案是这篇文章的Gilbert Le Blanc: Java: Convert String to packed decimal
此解决方案已在整个堆栈溢出中复制并粘贴了数百次,但存在严重缺陷:
public class PackedDecimal {
public static byte[] format(long number, int bytes) {
byte[] b = new byte[bytes];
final byte minusSign = 0x0D; // Minus
final byte noSign = 0x0F; // Unsigned
String s = Long.toString(number);
int length = s.length();
boolean isNegative = false;
if (s.charAt(0) == '-') {
isNegative = true;
s = s.substring(1);
length--;
}
int extraBytes = length - bytes + 1;
if (extraBytes < 0) {
// Pad extra byte positions with zero
for (int i = 0; i < -extraBytes; i++) {
b[i] = 0x00;
}
} else if (extraBytes > 0) {
// Truncate the high order digits of the number to fit
s = s.substring(extraBytes);
length -= extraBytes;
extraBytes = 0;
}
// Translate the string digits into bytes
for (int i = 0; i < length; i++) {
String digit = s.substring(i, i + 1);
b[i - extraBytes] = Byte.valueOf(digit);
}
// Add the sign byte
if (isNegative) {
b[bytes - 1] = minusSign;
} else {
b[bytes - 1] = noSign;
}
return b;
}
public static void main(String[] args) {
long number = -456L;
byte[] b = PackedDecimal.format(number, 5);
System.out.println("Number: " + number + ", packed: " + byteToString(b));
number = 0L;
b = PackedDecimal.format(number, 5);
System.out.println("Number: " + number + ", packed: " + byteToString(b));
number = 5823L;
b = PackedDecimal.format(number, 5);
System.out.println("Number: " + number + ", packed: " + byteToString(b));
number = 123456L;
b = PackedDecimal.format(number, 5);
System.out.println("Number: " + number + ", packed: " + byteToString(b));
}
public static String byteToString(byte[] b) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < b.length; i++) {
sb.append("0x");
sb.append(Integer.toHexString((int) b[i]).toUpperCase());
sb.append(" ");
}
return sb.toString();
}
}
这是测试结果。
Number: -456, packed: 0x0 0x4 0x5 0x6 0xD
Number: 0, packed: 0x0 0x0 0x0 0x0 0xF
Number: 5823, packed: 0x5 0x8 0x2 0x3 0xF
Number: 123456, packed: 0x3 0x4 0x5 0x6 0xF
此代码的问题是:
压缩十进制中使用的半字节数计算为 长度+ 1 +(如果半字节总数为奇数,则为1)
此代码将忽略所有这些内容。
以下是压缩十进制转换(l=length, half of bytes used)(p=number of half of bytes used after decimal point)
的一些示例:
(l=4)(p=0) +123 > 00123C (l=4)(p=0)-123 > 00123D
(l=4)(p=0)(Unsigned) 12345 > 12345F
(l=6)(p=2)(Unsigned) 12345.67 > 1234567F
(l=8)(p=2)(Unsigned) 12345.67 > 001234567F
(l=6)(p=3)(Unsigned) > 12345.67 > 2345670F
关于如何改进它的任何建议?
答案 0 :(得分:1)
有用于此的库。例如。您可以将IBM的JTOpen用于AS400兼容性。 blog post by Michael Wan-引用:
中描述了将Java BigDecimal转换为压缩的十进制然后返回的用法。/**
* Java BigDecimal to Packed Decimal
*/
//15 means total number of digits, 5 means number of decimal places
AS400PackedDecimal packedDecimal = new AS400PackedDecimal(15, 5);
BigDecimal javaBigDecimal = new BigDecimal("1000.12345");
byte[] convertedBytesArray = packedDecimal.toBytes(javaBigDecimal);
/**
* Packed Decimal to Java Big Decimal
*/
BigDecimal convertedBigDecimal = (BigDecimal)packedDecimal.toObject(convertedBytesArray);
我不知道的其他库:
答案 1 :(得分:0)
我用Google搜索了一下,发现:https://docs.oracle.com/cd/E18150_01/javadocs/CICS/com/stc/eways/cics/PackedDecimal.html
类PackedDecimal
确实具有方法toPackedDecimal
,该方法采用数字,因此采用Float
。
答案 2 :(得分:0)
有一个使用位操作将数字打包为COMP3(COBOL)格式的选项。下面的代码段仅适用于大型机COMP3格式包装
每个数字都以8位存储在最新系统中,但是COMP3保留2位数字。 例如,
1)123-将以2个字节存储-123将被视为+123-因此将以2个字节存储
2)1234-将以3个字节存储-123将被视为+1234-因此以3个字节存储,剩下的4位将为零
3)-123-将以2个字节存储-因此将以2个字节存储
byte[] packed = new byte[(data.length() - startAt) / 2 + 1];
int inIdx = chars.length - 1;
int outIdx = packed.length - 1;
int temp = (chars[(inIdx--)] & 0xF) << 4;
digit |= temp;
packed[(outIdx--)] = (byte)(digit & 0xFF);
for (; outIdx >= 0; --outIdx) {
if (inIdx < 0)
break;
if ((chars[inIdx] < 48) || (chars[inIdx] > 57))
{
logger.createErr("Invalid numeric character at " + inIdx);
return null;
}
digit = chars[(inIdx--)] & 0xF;
if (inIdx >= 0) {
temp = (chars[(inIdx--)] & 0xF) << 4;
digit |= temp;
}
packed[outIdx] = (byte)digit;
}
return packed;