使用字节或短
回答
int
变量在Java Card 2.2中是可选的,所以可以是是一个int
变量。许多实现并不打扰,可能是因为没有任何API调用处理整数。 javacardx.framework.math.BigNumber
类也是如此。如果你幸运的话,它是存在的,但它只会帮助你增加和乘法(但它可以使用原生函数来实现,这会使它更快)。
请注意,如果你只需要少量的功能,你可能会更好用一些局部变量short
并使用它们来执行计算内联。这具有性能更好的优点。由于不可能返回多个变量(并且Java参数按值传递),因此很难按值返回两个短路。
您可能会从中获得一些提示。使用long
数组来表示任意大小的整数的Java BigInteger
实现。一个问题是,正常的操作符在每次调用时会返回一个新实例。这在Java Card上不是一个好的选择,因为新的实例将在持久内存中创建。所以创建组合更容易
感谢提示,但我需要执行四个基本操作。 (即+ - * /) –
希望能尽快看到你的代码:) –
上面的评论是关于上面的'JCInteger'类的实现。 –
圣诞节特别回答。
充分利用单元测试只在Java SE测试,但至今。
需要用于实例化所述背衬阵列一些工作。
某些代码仍可以通过在衬里的左手操作数进行优化。
请注意,此代码使用*=
- 将答案分配给第一个变量 - 而不是*
,因为在Java Card运行时期间(在持久内存中创建它们时)创建对象实例并不是一个好主意。
全部剥离JavaDoc注释,因为它本来不会适应最大的职位大小。
/**
* Free for use by all, please keep this line and the author line intact.
*
* @author Maarten Bodewes
*/
public final class JCInteger {
private static final short BYTE_SIZE = 8;
private static final short SHORT_SIZE = 16;
private static final short INTEGER_SIZE = 32;
private static final short HIGH = 0;
private static final short LOW = 1;
private final short[] values;
private JCInteger(final byte memoryType) {
// TODO this should be backed by an array in RAM, using JCSystem.makeTransientByteArray()
// using either JCSystem.CLEAR_ON_RESET or JCSystem.CLEAR_ON_DESELECT
values = new short[(short) 2];
}
public static JCInteger createInstance(final byte memoryType) {
return new JCInteger(memoryType);
}
public JCInteger assign(final JCInteger rightHandOperand) {
values[HIGH] = rightHandOperand.values[HIGH];
values[LOW] = rightHandOperand.values[LOW];
return this;
}
public JCInteger assign(final short high, final short low) {
values[HIGH] = high;
values[LOW] = low;
return this;
}
public JCInteger assignSigned(final short signedValue) {
if (signedValue >= 0) {
values[HIGH] = (short) 0x0000;
} else {
values[HIGH] = (short) 0xFFFF;
}
values[LOW] = signedValue;
return this;
}
public JCInteger assignUnsigned(final short unsignedValue) {
values[HIGH] = (short) 0x0000;
values[LOW] = unsignedValue;
return this;
}
public short getHigh() {
// no pun intended
return values[HIGH];
}
public short getLow() {
return values[LOW];
}
public short[] getBackingShortArray() {
return values;
}
public JCInteger negate() {
// basically invert, then increase, note that -Integer.MIN_VALUE = Integer.MIN_VALUE (as it is in Java)
values[HIGH] = (short)~values[HIGH];
values[LOW] = (short)~values[LOW];
increment();
return this;
}
public JCInteger increment() {
values[LOW]++;
if (values[LOW] == 0) {
values[HIGH]++;
}
return this;
}
public JCInteger decrement() {
values[LOW]--;
if (values[LOW] == -1) {
values[HIGH]--;
}
return this;
}
public JCInteger add(final JCInteger y) {
addUnsignedLow(y.values[LOW]);
values[HIGH] += y.values[HIGH];
return this;
}
public JCInteger subtract(final JCInteger y) {
// subtracts by adding the negated i
// negation is identical to invert + increase
// however the increase is performed to the result of adding the inverted value
// invert
final short xlInv = (short) ~y.values[LOW];
final short xhInv = (short) ~y.values[HIGH];
// add
addUnsignedLow(xlInv);
values[HIGH] += xhInv;
// increase
increment();
return this;
}
public JCInteger multiply(JCInteger y) {
// uses the fact that:
// x * y =
// (x1 * 2^16 + x0) * (y1 * 2^16 + y0) =
// (x1 * y1 * 2^32) + x1 * y0 * 2^16 + x0 * y1 * 2^16 + x0 * y0 =
// x1 * y0 * 2^16 + x0 * y1 * 2^16 + x0 * y0 (because anything * 2^32 overflows all the bits) =
// x1 * y0 * 2^16 + x0 * y1 * 2^16 + z1 | z0 (where z1 = high 16 bits of x0 * y* and z0 is the low part) =
// r1 | r0 where r1 = x1 * y0 + x0 * y1 + z1 and r0 = z0
// r1 is only 16 bits so x1 * y0 and x0 * y0 may overflow, as may the additions, hopefully leaving the sign
// bit correctly set
boolean xPositive = this.isPositive();
if (!xPositive) {
this.negate();
}
final short xh = this.values[HIGH];
final short xl = this.values[LOW];
short yh = y.values[HIGH];
short yl = y.values[LOW];
// --- if signed then negate y ---
final boolean yPositive;
if ((yh & 0x8000) == 0) {
yPositive = true;
} else {
// negation (complement then increase)
yh = (short) ~yh;
yl = (short) ~yl;
yl++;
if (yl == 0) {
yh++;
}
yPositive = false;
}
// calculates z1 and z0 and stores it in the current values
multiplyUnsigned(xl, yl, values);
// perform the calculation for the high parts
values[HIGH] += (short) (xh * yl + xl * yh);
// make sure we return a correctly signed value
if ((xPositive && !yPositive) || (!xPositive && yPositive)) {
this.negate();
}
return this;
}
public JCInteger divide(JCInteger y) {
// --- pre-calculations on y ---
// put y in yh and yl
short yh = y.values[HIGH];
short yl = y.values[LOW];
if (yh == 0 && yl == 0) {
// division by zero
throw new ArithmeticException();
}
final boolean yPositive;
if ((yh & 0x8000) == 0) {
yPositive = true;
} else {
// negation (complement then increase)
yh = (short) ~yh;
yl = (short) ~yl;
yl++;
if (yl == 0) {
yh++;
}
yPositive = false;
}
final short divisorSize = (short) (INTEGER_SIZE - numberOfLeadingZeros(yh, yl));
// --- pre-calculations on x ---
final boolean xPositive = this.isPositive();
if (!xPositive) {
this.negate();
}
final short dividentSize = (short) (INTEGER_SIZE - numberOfLeadingZeros());
// --- setup the maximum number of shifts ---
final short maxShifts = (short) (dividentSize - divisorSize);
// --- slightly superfluous check if divisor is higher than dividend ---
if (maxShifts < 0) {
// return 0, no division can be performed
values[HIGH] = 0;
values[LOW] = 0;
return this;
}
// --- shift divisor left until the highest bit is aligned with the highest bit of the dividend ---
if (maxShifts <= JCInteger.SHORT_SIZE) {
yh = (short) (((yl & 0xFFFF) >>> (SHORT_SIZE - maxShifts)) | (yh << maxShifts));
yl <<= maxShifts;
} else {
yh = (short) (yl << (maxShifts - SHORT_SIZE));
yl = 0;
}
short rh = 0, rl = 0;
for (short i = maxShifts; i >= 0; i--) {
final short xho = values[HIGH];
final short xlo = values[LOW];
// --- subtract (add complement and increment does the job) ---
// add complement
addUnsignedLow((short) ~yl);
values[HIGH] += (short) ~yh;
// increase to create subtraction
increment();
if (isPositive()) {
// --- we have subtracted y * 2^n, so include 2^n to the result ---
if (i >= SHORT_SIZE) {
rh |= 1 << (i - SHORT_SIZE);
} else {
rl |= 1 << i;
}
} else {
// --- we could not subtract, so restore ---
values[HIGH] = xho;
values[LOW] = xlo;
}
// --- shift right by 1 ---
// first do low shift as high shift changes value
yl = (short) ((yh << (JCInteger.SHORT_SIZE - 1)) | ((yl & 0xFFFF) >>> 1));
yh = (short) ((yh & 0xFFFF) >>> 1);
}
values[HIGH] = rh;
values[LOW] = rl;
// make sure we return a correctly signed value (may mess up sign bit on overflows?)
if ((xPositive && !yPositive) || (!xPositive && yPositive)) {
this.negate();
}
return this;
}
public JCInteger remainder(JCInteger y) {
// --- pre-calculations on y ---
// put y in yh and yl
short yh = y.values[HIGH];
short yl = y.values[LOW];
if (yh == 0 && yl == 0) {
// division by zero
throw new ArithmeticException();
}
if ((yh & 0x8000) != 0) {
// negation (complement then increase)
yh = (short) ~yh;
yl = (short) ~yl;
yl++;
if (yl == 0) {
yh++;
}
}
final short divisorSize = (short) (INTEGER_SIZE - numberOfLeadingZeros(yh, yl));
// --- pre-calculations on x ---
final boolean xPositive = this.isPositive();
if (!xPositive) {
this.negate();
}
final short dividentSize = (short) (INTEGER_SIZE - numberOfLeadingZeros());
// --- setup the maximum number of shifts ---
final short maxShifts = (short) (dividentSize - divisorSize);
// --- slightly superfluous check if divisor is higher than dividend ---
if (maxShifts < 0) {
if (!xPositive) {
return this.negate();
}
return this;
}
// --- shift divisor left until the highest bit is aligned with the highest bit of the dividend ---
if (maxShifts <= JCInteger.SHORT_SIZE) {
yh = (short) (((yl & 0xFFFF) >>> (SHORT_SIZE - maxShifts)) | (yh << maxShifts));
yl <<= maxShifts;
} else {
yh = (short) (yl << (maxShifts - SHORT_SIZE));
yl = 0;
}
for (short i = maxShifts; i >= 0; i--) {
final short xho = values[HIGH];
final short xlo = values[LOW];
// --- subtract (add complement and increment does the job) ---
// add complement
addUnsignedLow((short) ~yl);
values[HIGH] += (short) ~yh;
// increase to create subtraction
increment();
if (!isPositive()) {
values[HIGH] = xho;
values[LOW] = xlo;
}
// --- shift right by 1 ---
// first do low shift as high shift changes value
yl = (short) ((yh << (JCInteger.SHORT_SIZE - 1)) | ((yl & 0xFFFF) >>> 1));
yh = (short) ((yh & 0xFFFF) >>> 1);
}
if (!xPositive) {
negate();
}
return this;
}
public JCInteger leftShift(short shiftDistance) {
shiftDistance = (short) (shiftDistance & 0x1F);
if (shiftDistance == 0) {
return this;
}
final short low = values[LOW];
final short high = values[HIGH];
// TODO test if we can do without if on Java Card (is integer value calculated? cannot really be.
if (shiftDistance < SHORT_SIZE) {
values[HIGH] = (short) (((low & 0xFFFF) >>> (SHORT_SIZE - shiftDistance)) | (high << shiftDistance));
values[LOW] <<= shiftDistance;
} else {
values[HIGH] = (short) (low << (shiftDistance - SHORT_SIZE));
values[LOW] = 0;
}
return this;
}
public JCInteger signedRightShift(short shiftDistance) {
shiftDistance = (short) (shiftDistance & 0x1F);
if (shiftDistance == 0) {
return this;
}
final short low = values[LOW];
final short high = values[HIGH];
if (shiftDistance < SHORT_SIZE) {
values[HIGH] = (short) (high >>> shiftDistance);
values[LOW] = (short) ((high << (SHORT_SIZE - shiftDistance)) | ((low & 0xFFFF) >>> shiftDistance));
} else {
if ((high & 0x8000) == 0) {
values[HIGH] = 0;
values[LOW] = (short) ((high & 0xFFFF) >>> (shiftDistance - SHORT_SIZE));
} else {
values[HIGH] = (short) 0xFFFF;
values[LOW] = (short) (high >>> (shiftDistance - SHORT_SIZE));
}
}
return this;
}
public JCInteger unsignedRightShift(short shiftDistance) {
shiftDistance = (short) (shiftDistance & 0x1F);
if (shiftDistance == 0) {
return this;
}
final short low = values[LOW];
final short high = values[HIGH];
if (shiftDistance < SHORT_SIZE) {
values[HIGH] = (short) ((high & 0xFFFF) >>> shiftDistance);
values[LOW] = (short) ((high << (SHORT_SIZE - shiftDistance)) | ((low & 0xFFFF) >>> shiftDistance));
} else {
values[HIGH] = 0;
values[LOW] = (short) ((high & 0xFFFF) >>> (shiftDistance - SHORT_SIZE));
}
return this;
}
public JCInteger complement() {
this.values[HIGH] = (short) ~this.values[HIGH];
this.values[LOW] = (short) ~this.values[LOW];
return this;
}
public JCInteger xor(final JCInteger y) {
this.values[HIGH] ^= y.values[HIGH];
this.values[LOW] ^= y.values[LOW];
return this;
}
public JCInteger and(final JCInteger y) {
this.values[HIGH] &= y.values[HIGH];
this.values[LOW] &= y.values[LOW];
return this;
}
public JCInteger or(final JCInteger y) {
this.values[HIGH] |= y.values[HIGH];
this.values[LOW] |= y.values[LOW];
return this;
}
public short signum() {
if (values[HIGH] == 0 && values[LOW] == 0) {
return 0;
}
// get sign bit (>>> 15) negate, -1 for neg, 0 for pos, then times 2 (<< 2) which leaves -2 for neg 0 for pos
// and finally add 1, to get the result -1 or 1 for negative and positive, respectively
return (short) ((-((values[HIGH] >>> 15) & 1) * 2) + 1);
}
public short numberOfLeadingZeros() {
short t = values[HIGH];
if (t != 0) {
for (short i = 0; i < SHORT_SIZE; i++) {
if (t < 0) {
return i;
}
t <<= 1;
}
}
t = values[LOW];
if (t != 0) {
for (short i = SHORT_SIZE; i < INTEGER_SIZE; i++) {
if (t < 0) {
return i;
}
t <<= 1;
}
}
return INTEGER_SIZE;
}
public short compareTo(JCInteger anotherInteger) {
final short xh = values[HIGH];
final short yh = anotherInteger.values[HIGH];
if (xh < yh) {
return -1;
} else if (xh > yh) {
return 1;
}
// --- xh == yh ---
final short xl = values[LOW];
final short yl = anotherInteger.values[LOW];
// TODO think of better way than four ifs
if (xl < 0 && yl >= 0) {
return 1;
} else if (xl >= 0 && yl < 0) {
return -1;
} else if (xl > yl) {
return 1;
} else if (xl < yl) {
return -1;
}
return 0;
}
public boolean equals(Object obj) {
if (!(obj instanceof JCInteger)) {
return false;
}
final JCInteger otherInt = (JCInteger) obj;
return values[HIGH] == otherInt.values[HIGH]
&& values[LOW] == otherInt.values[LOW];
}
public short encode(final byte[] bArray, short bOff) {
// use javacard.framework.Util.setShort() instead
bArray[bOff++] = (byte) (values[HIGH] >>> BYTE_SIZE);
bArray[bOff++] = (byte) (values[HIGH] & 0xFF);
bArray[bOff++] = (byte) (values[LOW] >>> BYTE_SIZE);
bArray[bOff++] = (byte) (values[LOW] & 0xFF);
return bOff;
}
public JCInteger decode(final byte[] bArray, short bOff) {
values[HIGH] = (short) ((bArray[bOff++] << BYTE_SIZE) | (bArray[bOff++] & 0xFF));
values[LOW] = (short) ((bArray[bOff++] << BYTE_SIZE) | (bArray[bOff++] & 0xFF));
return this;
}
private boolean isPositive() {
return (values[HIGH] & 0x8000) == 0;
}
private void addUnsignedLow(final short yl) {
final short xl = values[LOW];
values[HIGH] += carryOnUnsignedAddition(xl, yl);
values[LOW] = (short) (xl + yl);
}
private static short carryOnUnsignedAddition(final short x, final short y) {
// implementation without any conditionals on the highest bits of x, y and r = x + y
final short r = (short) (x + y);
// uses only the sign bit on the variables including the result to see if carry will happen
return (short) ((((x & y) | (x & ~y & ~r) | (~x & y & ~r)) >>> 15) & 1);
}
private static short[] multiplyUnsigned(short x, short y, short[] r) {
// uses the fact that:
// x * y =
// (x1 * 2^8 + x0) * (y1 * 2^8 + y0) =
// (x1 * y1 * 2^16) + x1 * y0 * 2^8 + x0 * y1 * 2^8 + x0 * y0
final short x1 = (short) ((x >>> BYTE_SIZE) & 0xFF);
final short x0 = (short) (x & 0xFF);
final short y1 = (short) ((y >>> BYTE_SIZE) & 0xFF);
final short y0 = (short) (y & 0xFF);
// TODO check uppiest bit of rh and rl
// calculate z2 * 2^(2 * 8) = x1 * y1 * 2^(2 * 8) = x1 * y1 << 16,
// store it as partial result in rh
short rh = (short) (x1 * y1);
// calculate z0 = x0 * y0
short rl = (short) (x0 * y0);
short toAdd, result;
// calculate x1 * y0* 2^8
short x1y0 = (short) (x1 * y0);
rh += (x1y0 >>> 8) & 0xFF;
toAdd = (short) ((x1y0 << 8) & 0xFF00);
result = (short) (rl + toAdd);
rh += carryOnUnsignedAddition(rl, toAdd);
rl = result;
// calculate x0 * y1* 2^8
short x0y1 = (short) (x0 * y1);
rh += (x0y1 >>> 8) & 0xFF;
toAdd = (short) ((x0y1 << 8) & 0xFF00);
result = (short) (rl + toAdd);
rh += carryOnUnsignedAddition(rl, toAdd);
rl = result;
r[HIGH] = rh;
r[LOW] = rl;
return r;
}
private static short numberOfLeadingZeros(short ih, short il) {
if (ih != 0) {
for (short i = 0; i < SHORT_SIZE; i++) {
if (ih < 0) {
return i;
}
ih <<= 1;
}
}
if (il != 0) {
for (short i = SHORT_SIZE; i < INTEGER_SIZE; i++) {
if (il < 0) {
return i;
}
il <<= 1;
}
}
return INTEGER_SIZE;
}
}
看起来很有希望。你可以请你的单元测试的地方,所以我可以在模拟器上测试它? –
paulc说:“你为你的有趣和有用的职位。我还没有测试过所有的功能,但是当我在JAVA SE上测试剩余函数时它确定,但是例如对于JavaCard它失败了” –
- 1. 将字节转换为短或整数
- 2. Java - 从短到字节[2]使用LITTLE_ENDIAN
- 3. 为什么Java中没有字节或短文字?
- 4. C中2个字节的字节缩短为2个字节?
- 5. 字节,短型的好处
- 6. Java短到字节数组
- 7. 转换字节[]为简短[]
- 8. 签订短字节C++
- 9. 图像损坏或使用字节[]和varbinary(最大)时在NHibernate的截短
- 10. 使用编年史图和字节[]或字节缓冲区
- 11. 级联字节到整数或短保留符号
- 12. 在C++中使用char *或void *或其他字节字段?
- 13. MYSQL - int或短字符串?
- 14. Android AudioRecord - 使用短阵列还是字节数组?
- 15. 如何使用短int的左右字节?
- 16. 在C#中使用字节/短等的任何理由?
- 17. 高效地将音频字节 - 字节[]缩短[]
- 18. jQuery的缩短长度(兆字节转换到千兆字节)
- 19. 在Android中短字节和字节到空格的转换
- 20. 字节数组到一个短
- 21. C#短,字节发生在86
- 22. 解析短字节数组(蓝牙)
- 23. 字节和短裤的类型问题
- 24. 字节设置一个无符号短
- 25. 双转换到短到字节
- 26. Java位移位,短转换为字节
- 27. 为什么短为2字节对齐?
- 28. 为什么使用memset手动设置字节时字符串缩短?
- 29. 使用SMPP或/和SS7的短信
- 30. 指定字节或int到列表<int>或字节C#
我可以做一些这样的事情,但乘法,除法和模数相当棘手。你有什么要求? –
@owlstead其实我需要全部四项基本操作。 (+ -/*) –