1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc
.squirreljme
.jvm
;
12 import cc
.squirreljme
.jvm
.mle
.MathShelf
;
13 import cc
.squirreljme
.runtime
.cldc
.annotation
.SquirrelJMEVendorApi
;
14 import cc
.squirreljme
.runtime
.cldc
.debug
.Debugging
;
17 * Software math operations on 64-bit integer types.
22 @SuppressWarnings("MagicNumber")
23 public final class SoftLong
45 public static long add(int __al
, int __ah
, int __bl
, int __bh
)
47 // Add the higher/lower parts
51 // If the low addition carried a bit over, then set that bit in the
53 if ((cl
+ 0x80000000) < (__al
+ 0x80000000))
57 return MathShelf
.longPack(cl
, ch
);
69 public static long add(long __a
, long __b
)
71 return SoftLong
.add(MathShelf
.longUnpackLow(__a
),
72 MathShelf
.longUnpackHigh(__a
),
73 MathShelf
.longUnpackLow(__b
),
74 MathShelf
.longUnpackHigh(__b
));
88 public static long and(int __al
, int __ah
, int __bl
, int __bh
)
90 return MathShelf
.longPack(__al
& __bl
, __ah
& __bh
);
101 @SquirrelJMEVendorApi
102 public static long and(long __a
, long __b
)
104 return SoftLong
.add(MathShelf
.longUnpackLow(__a
),
105 MathShelf
.longUnpackHigh(__a
),
106 MathShelf
.longUnpackLow(__b
),
107 MathShelf
.longUnpackHigh(__b
));
111 * Compares two values.
114 * @param __ah A high.
116 * @param __bh B high.
117 * @return The result.
120 @SquirrelJMEVendorApi
121 public static int cmp(int __al
, int __ah
, int __bl
, int __bh
)
123 // Compare high values firsts
126 else if (__ah
> __bh
)
129 // Compare low values with unsigned comparison
130 __al
+= Integer
.MIN_VALUE
;
131 __bl
+= Integer
.MIN_VALUE
;
134 else if (__al
> __bl
)
140 * Compares two values.
144 * @return The result.
147 @SquirrelJMEVendorApi
148 public static int cmp(long __a
, long __b
)
150 return SoftLong
.cmp(MathShelf
.longUnpackLow(__a
),
151 MathShelf
.longUnpackHigh(__a
),
152 MathShelf
.longUnpackLow(__b
),
153 MathShelf
.longUnpackHigh(__b
));
157 * Divides two values.
160 * @param __ah A high.
162 * @param __bh B high.
163 * @return The result.
166 @SquirrelJMEVendorApi
167 public static long div(int __al
, int __ah
, int __bl
, int __bh
)
170 if (__bh
== 0 && __bl
== 0)
171 throw new ArithmeticException();
173 return SoftLong
.__div(false, __al
, __ah
, __bl
, __bh
);
177 * Divides two values.
181 * @return The result.
184 @SquirrelJMEVendorApi
185 public static long div(long __a
, long __b
)
187 return SoftLong
.div(MathShelf
.longUnpackLow(__a
),
188 MathShelf
.longUnpackHigh(__a
),
189 MathShelf
.longUnpackLow(__b
),
190 MathShelf
.longUnpackHigh(__b
));
194 * Multiplies two long values.
197 * @param __ah A high.
199 * @param __bh B high.
200 * @return The result.
203 @SquirrelJMEVendorApi
204 public static long mul(int __al
, int __ah
, int __bl
, int __bh
)
206 // Are both sides negative?
207 if (((__ah
& __bh
) & 0x8000_
0000) != 0)
209 // Negate and check for overflow
215 // Negate and check for overflow
222 return SoftLong
.__mul(__al
, __ah
, __bl
, __bh
);
225 // Perform the calculation
226 return SoftLong
.__mul(__al
, __ah
, __bl
, __bh
);
230 * Multiplies two long values.
234 * @return The result.
237 @SquirrelJMEVendorApi
238 public static long mul(long __a
, long __b
)
240 return SoftLong
.mul(MathShelf
.longUnpackLow(__a
),
241 MathShelf
.longUnpackHigh(__a
),
242 MathShelf
.longUnpackLow(__b
),
243 MathShelf
.longUnpackHigh(__b
));
250 * @param __ah A high.
251 * @return The result.
254 @SquirrelJMEVendorApi
255 public static long neg(int __al
, int __ah
)
257 // Negate and check for overflow
264 return MathShelf
.longPack(__al
, __ah
);
271 * @return The result.
274 @SquirrelJMEVendorApi
275 public static long neg(long __a
)
277 return SoftLong
.mul(MathShelf
.longUnpackLow(__a
),
278 MathShelf
.longUnpackHigh(__a
));
285 * @param __ah A high.
287 * @param __bh B high.
288 * @return The result.
291 @SquirrelJMEVendorApi
292 public static long or(int __al
, int __ah
, int __bl
, int __bh
)
294 return MathShelf
.longPack(__al
| __bl
, __ah
| __bh
);
302 * @return The result.
305 @SquirrelJMEVendorApi
306 public static long or(long __a
, long __b
)
308 return SoftLong
.or(MathShelf
.longUnpackLow(__a
),
309 MathShelf
.longUnpackHigh(__a
),
310 MathShelf
.longUnpackLow(__b
),
311 MathShelf
.longUnpackHigh(__b
));
315 * Remainders a value.
318 * @param __ah A high.
320 * @param __bh B high.
321 * @return The result.
324 @SquirrelJMEVendorApi
325 public static long rem(int __al
, int __ah
, int __bl
, int __bh
)
328 if (__bh
== 0 && __bl
== 0)
329 throw new ArithmeticException();
331 return SoftLong
.__div(true, __al
, __ah
, __bl
, __bh
);
335 * Remainders a value.
339 * @return The result.
342 @SquirrelJMEVendorApi
343 public static long rem(long __a
, long __b
)
345 return SoftLong
.rem(MathShelf
.longUnpackLow(__a
),
346 MathShelf
.longUnpackHigh(__a
),
347 MathShelf
.longUnpackLow(__b
),
348 MathShelf
.longUnpackHigh(__b
));
352 * Shifts value left by bits.
355 * @param __ah A high.
356 * @param __s Shift amount.
357 * @return The result.
360 @SquirrelJMEVendorApi
361 public static long shl(int __al
, int __ah
, int __s
)
363 // Mask the shift amount
368 return MathShelf
.longPack(__al
, __ah
);
370 // Shifting all the low bits to the high bits
372 return MathShelf
.longPack(0, __al
<< (__s
- 32));
374 // Merge of bits (shift in range of 1-31)
375 return MathShelf
.longPack((__al
<< __s
),
376 (__ah
<< __s
) | (__al
>>> (32 - __s
)));
380 * Shifts value left by bits.
383 * @param __s Shift amount.
384 * @return The result.
387 @SquirrelJMEVendorApi
388 public static long shl(long __a
, int __s
)
390 return SoftLong
.shl(MathShelf
.longUnpackLow(__a
),
391 MathShelf
.longUnpackHigh(__a
), __s
);
395 * Shifts value right by bits.
398 * @param __ah A high.
399 * @param __s Shift amount.
400 * @return The result.
403 @SquirrelJMEVendorApi
404 public static long shr(int __al
, int __ah
, int __s
)
406 // Mask the shift amount
411 return MathShelf
.longPack(__al
, __ah
);
413 // Shifting all the high bits low
415 return MathShelf
.longPack(__ah
>> (__s
- 32),
416 (__ah
& 0x80000000) >> 31);
418 // Merge of bits (shift in range of 1-31)
419 return MathShelf
.longPack((__ah
<< (32 - __s
)) | (__al
>>> __s
),
424 * Shifts value right by bits.
427 * @param __s Shift amount.
428 * @return The result.
431 @SquirrelJMEVendorApi
432 public static long shr(long __a
, int __s
)
434 return SoftLong
.shr(MathShelf
.longUnpackLow(__a
),
435 MathShelf
.longUnpackHigh(__a
), __s
);
442 * @param __ah A high.
444 * @param __bh B high.
445 * @return The result.
448 @SquirrelJMEVendorApi
449 public static long sub(int __al
, int __ah
, int __bl
, int __bh
)
451 // The same as add, but the second operand is negated
452 // Negate and check for overflow
458 // Add the higher/lower parts
459 int ch
= __ah
+ __bh
;
460 int cl
= __al
+ __bl
;
462 // If the low addition carried a bit over, then set that bit in the
464 if ((cl
+ 0x80000000) < (__al
+ 0x80000000))
468 return MathShelf
.longPack(cl
, ch
);
476 * @return The result.
479 @SquirrelJMEVendorApi
480 public static long sub(long __a
, long __b
)
482 return SoftLong
.sub(MathShelf
.longUnpackLow(__a
),
483 MathShelf
.longUnpackHigh(__a
),
484 MathShelf
.longUnpackLow(__b
),
485 MathShelf
.longUnpackHigh(__b
));
489 * Converts to double.
491 * @param __al Low value.
492 * @param __ah High value.
493 * @return The result.
496 @SquirrelJMEVendorApi
497 public static double toDouble(int __al
, int __ah
)
499 throw Debugging
.todo();
503 * Converts to double.
505 * @param __a A value.
506 * @return The result.
509 @SquirrelJMEVendorApi
510 public static double toDouble(long __a
)
512 return SoftLong
.toDouble(MathShelf
.longUnpackLow(__a
),
513 MathShelf
.longUnpackHigh(__a
));
520 * @param __ah A high.
521 * @return The result.
524 @SquirrelJMEVendorApi
525 public static float toFloat(int __al
, int __ah
)
527 throw Debugging
.todo();
533 * @param __a A value.
534 * @return The result.
537 @SquirrelJMEVendorApi
538 public static float toFloat(long __a
)
540 return SoftLong
.toFloat(MathShelf
.longUnpackLow(__a
),
541 MathShelf
.longUnpackHigh(__a
));
545 * Converts to integer.
548 * @param __ah A high.
549 * @return The result.
552 @SquirrelJMEVendorApi
553 public static int toInteger(int __al
, @SuppressWarnings("unused") int __ah
)
555 // Just return the low order bits
560 * Converts to integer.
562 * @param __a A value.
563 * @return The result.
566 @SquirrelJMEVendorApi
567 public static int toInteger(long __a
)
569 return SoftLong
.toInteger(MathShelf
.longUnpackLow(__a
),
570 MathShelf
.longUnpackHigh(__a
));
574 * Shifts value bits right unsigned.
577 * @param __ah A high.
578 * @param __s Shift amount.
579 * @return The result.
582 @SquirrelJMEVendorApi
583 public static long ushr(int __al
, int __ah
, int __s
)
585 // Mask the shift amount
590 return MathShelf
.longPack(__al
, __ah
);
592 // Shifting all the high bits low
594 return MathShelf
.longPack(__ah
>>> (__s
- 32), 0);
596 // Merge of bits (shift in range of 1-31)
597 return MathShelf
.longPack((__ah
<< (32 - __s
)) | (__al
>>> __s
),
602 * Shifts value bits right unsigned.
605 * @param __s Shift amount.
606 * @return The result.
609 @SquirrelJMEVendorApi
610 public static long ushr(long __a
, int __s
)
612 return SoftLong
.ushr(MathShelf
.longUnpackLow(__a
),
613 MathShelf
.longUnpackHigh(__a
), __s
);
617 * Exclusive ORs two values.
620 * @param __ah A high.
622 * @param __bh B high.
623 * @return The result.
626 @SquirrelJMEVendorApi
627 public static long xor(int __al
, int __ah
, int __bl
, int __bh
)
629 return MathShelf
.longPack(__al ^ __bl
, __ah ^ __bh
);
633 * Exclusive ORs two values.
637 * @return The result.
640 @SquirrelJMEVendorApi
641 public static long xor(long __a
, long __b
)
643 return SoftLong
.xor(MathShelf
.longUnpackLow(__a
),
644 MathShelf
.longUnpackHigh(__a
),
645 MathShelf
.longUnpackLow(__b
),
646 MathShelf
.longUnpackHigh(__b
));
650 * Divides and remainders two values.
652 * @param __doRem Return the remainder?
653 * @param __nl The numerator, low.
654 * @param __nh The numerator, high.
655 * @param __dl The denominator, low.
656 * @param __dh The denominator, high.
657 * @return The result.
660 @SuppressWarnings("CommentedOutCode")
661 private static long __div(boolean __doRem
, int __nl
, int __nh
,
664 /* {@squirreljme.error ZZ4z Divide by zero.} */
665 if (__dl
== 0 && __dh
== 0)
666 throw new ArithmeticException("ZZ4z");
668 // Wikipedia (http://en.wikipedia.org/wiki/Division_%28digital%29)
669 // if D == 0 then throw DivisionByZeroException end
670 // Q := 0 # initialize quotient and remainder to zero
672 // for i = n-1...0 do # " where n is no of bits "
673 // R := R << 1 # left-shift R by 1 bit
674 // R(0) := N(i) # set the least-significant bit
675 // # of R equal to bit i of the numerator
681 // long qx = 0, rx = 0;
683 // High and low resultant values
689 // Disallow division by zero
693 // Results in a negative? Only results in such if either side is
695 boolean negNum
= ((__nh
& 0x8000_
0000) != 0);
696 boolean negDem
= ((__dh
& 0x8000_
0000) != 0);
697 boolean isNeg
= (negNum
!= negDem
);
699 // Make the numerator positive, if negative
702 // Negate and check for overflow
709 // Make the denominator positive, if negative
712 // Negate and check for overflow
719 // __dl and __dh for unsigned compare
720 int dlUnsigned
= __dl
+ Integer
.MIN_VALUE
;
721 int dhUnsigned
= __dh
+ Integer
.MIN_VALUE
;
724 for (int i
= 63, hMask
= 0xFFFF_FFFF
, lMask
= 0;
726 i
--, hMask
>>>= 1, lMask
= ((lMask
>> 1) | 0x8000_
0000))
729 // rx &= 0xFFFFFFFFFFFFFFFEL;
734 // rx |= ((__nx >>> i) & 1L); ... only take the lowest bit!
737 // ! rl |= ((__nh >>> (i - 32)) & 0x1);
739 // ! rl |= ((__nl >>> i) & 0x1);
740 // faster using masking:
741 // ! rl |= (((__nh & hMask) >>> i) & 0x1);
742 // ! rl |= (((__nl & lMask) >>> i) & 0x1);
743 rl
|= ((((__nh
& hMask
) | (__nl
& lMask
)) >>> i
) & 0x1);
745 // Unsigned comparison (shift by 0x8000_0000__0000_0000L)
746 // if ((rx + Long.MIN_VALUE) >= (__dx + Long.MIN_VALUE))
747 /*if (SoftLong.cmp(rl, rh + Integer.MIN_VALUE,
748 __dl, __dh + Integer.MIN_VALUE) >= 0)*/
749 int cmp
= (rh
+ Integer
.MIN_VALUE
) - dhUnsigned
;
751 (cmp
> 0 || // Is just a bigger number overall?
752 rl
+ Integer
.MIN_VALUE
>= dlUnsigned
))
755 // The same as add, but the second operand is negated
756 // Negate and check for overflow
758 int bl
= (~__dl
+ 1);
762 // Add the higher/lower parts
766 // If the low addition carried a bit over, then set that bit in
768 if ((cl
+ 0x80000000) < (rl
+ 0x80000000))
776 qh
|= (1 << (i
- 32));
782 // Return the remainder if needed, note the remainder is negative only
783 // if the numerator is negative
785 return (negNum ? SoftLong
.neg(rl
, rh
) :
786 MathShelf
.longPack(rl
, rh
));
788 // Return, normalize negative if needed
789 return (isNeg ? SoftLong
.neg(ql
, qh
) : MathShelf
.longPack(ql
, qh
));
793 * Multiplies two long values, note that this will fail if both A and B
794 * are negative. The values must either be both positive or only one is
798 * @param __ah A high.
800 * @param __bh B high.
801 * @return The result.
804 private static long __mul(int __al
, int __ah
, int __bl
, int __bh
)
807 int a
= (__ah
>>> 16);
808 int b
= (__ah
& 0xFFFF);
809 int c
= (__al
>>> 16);
810 int d
= (__al
& 0xFFFF);
813 int w
= (__bh
>>> 16);
814 int x
= (__bh
& 0xFFFF);
815 int y
= (__bl
>>> 16);
816 int z
= (__bl
& 0xFFFF);
818 // Effectively this is long multiplication
819 // Multiplication in two's complement form is the same in both
820 // signed and unsigned, so we need not worry about signs and just treat
821 // this all as unsigned. Each fragment is 16 of the 64 bits.
824 // ============|===.===,===.===
827 // b_w b_x|b_y.b_z, .
828 // a_w a_x a_y|a_z. , .
829 // ============|===.===,===.===
830 // DISCARD m. n, o. p
832 // Overflow storage, since we want a temporary and we do not want to
833 // make any allocations or otherwise for 64-bit values. This keeps it
834 // all in 32-bit and handles the various situations.
837 // Multiply and add all the parts together
842 // int o = (d * y) + (c * z) + (p >>> 16);
843 int o
= over
+ (d
* y
);
845 o
= (o
& 0xFFFF) + (c
* z
);
848 // int n = (d * x) + (c * y) + (b * z) + (o >>> 16);
849 int n
= over
+ (d
* x
);
851 n
= (n
& 0xFFFF) + (c
* y
);
853 n
= (n
& 0xFFFF) + (b
* z
);
856 // int m = (d * w) + (c * x) + (b * y) + (a * z) + (n >>> 16);
857 // We need not care about overflow here, because it will all be
859 int m
= over
+ (d
* w
) + (c
* x
) + (b
* y
) + (a
* z
);
861 // Combine the resultant parts
862 return MathShelf
.longPack((o
<< 16) | (p
& 0xFFFF),
863 (m
<< 16) | (n
& 0xFFFF));