Add blank classes for DoJa graphics3d.
[SquirrelJME.git] / modules / cldc-compact / src / main / java / cc / squirreljme / jvm / SoftLong.java
blob5d71c17e457c0326a809f3c1e924def2db732c3c
1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
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;
16 /**
17 * Software math operations on 64-bit integer types.
19 * @since 2019/05/24
21 @SquirrelJMEVendorApi
22 @SuppressWarnings("MagicNumber")
23 public final class SoftLong
25 /**
26 * Not used.
28 * @since 2019/05/24
30 private SoftLong()
34 /**
35 * Adds two values.
37 * @param __al A low.
38 * @param __ah A high.
39 * @param __bl B low.
40 * @param __bh B high.
41 * @return The result.
42 * @since 2019/05/24
44 @SquirrelJMEVendorApi
45 public static long add(int __al, int __ah, int __bl, int __bh)
47 // Add the higher/lower parts
48 int ch = __ah + __bh,
49 cl = __al + __bl;
51 // If the low addition carried a bit over, then set that bit in the
52 // high part
53 if ((cl + 0x80000000) < (__al + 0x80000000))
54 ch++;
56 // Return result
57 return MathShelf.longPack(cl, ch);
60 /**
61 * Adds two values.
63 * @param __a A.
64 * @param __b B.
65 * @return The result.
66 * @since 2023/08/02
68 @SquirrelJMEVendorApi
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));
77 /**
78 * Ands two values.
80 * @param __al A low.
81 * @param __ah A high.
82 * @param __bl B low.
83 * @param __bh B high.
84 * @return The result.
85 * @since 2019/05/24
87 @SquirrelJMEVendorApi
88 public static long and(int __al, int __ah, int __bl, int __bh)
90 return MathShelf.longPack(__al & __bl, __ah & __bh);
93 /**
94 * Ands two values.
96 * @param __a A.
97 * @param __b B.
98 * @return The result.
99 * @since 2023/08/02
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.
113 * @param __al A low.
114 * @param __ah A high.
115 * @param __bl B low.
116 * @param __bh B high.
117 * @return The result.
118 * @since 2019/05/24
120 @SquirrelJMEVendorApi
121 public static int cmp(int __al, int __ah, int __bl, int __bh)
123 // Compare high values firsts
124 if (__ah < __bh)
125 return -1;
126 else if (__ah > __bh)
127 return 1;
129 // Compare low values with unsigned comparison
130 __al += Integer.MIN_VALUE;
131 __bl += Integer.MIN_VALUE;
132 if (__al < __bl)
133 return -1;
134 else if (__al > __bl)
135 return 1;
136 return 0;
140 * Compares two values.
142 * @param __a A.
143 * @param __b B.
144 * @return The result.
145 * @since 2023/08/02
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.
159 * @param __al A low.
160 * @param __ah A high.
161 * @param __bl B low.
162 * @param __bh B high.
163 * @return The result.
164 * @since 2019/05/24
166 @SquirrelJMEVendorApi
167 public static long div(int __al, int __ah, int __bl, int __bh)
169 // Dividing by zero?
170 if (__bh == 0 && __bl == 0)
171 throw new ArithmeticException();
173 return SoftLong.__div(false, __al, __ah, __bl, __bh);
177 * Divides two values.
179 * @param __a A.
180 * @param __b B.
181 * @return The result.
182 * @since 2023/08/02
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.
196 * @param __al A low.
197 * @param __ah A high.
198 * @param __bl B low.
199 * @param __bh B high.
200 * @return The result.
201 * @since 2019/05/24
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
210 __ah = (~__ah);
211 __al = (~__al + 1);
212 if (__al == 0)
213 __ah++;
215 // Negate and check for overflow
216 __bh = (~__bh);
217 __bl = (~__bl + 1);
218 if (__bl == 0)
219 __bh++;
221 // Return result
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.
232 * @param __a A.
233 * @param __b B.
234 * @return The result.
235 * @since 2023/08/02
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));
247 * Negates a value.
249 * @param __al A low.
250 * @param __ah A high.
251 * @return The result.
252 * @since 2019/05/24
254 @SquirrelJMEVendorApi
255 public static long neg(int __al, int __ah)
257 // Negate and check for overflow
258 __ah = (~__ah);
259 __al = (~__al + 1);
260 if (__al == 0)
261 __ah++;
263 // Return result
264 return MathShelf.longPack(__al, __ah);
268 * Negates a value.
270 * @param __a A.
271 * @return The result.
272 * @since 2023/08/02
274 @SquirrelJMEVendorApi
275 public static long neg(long __a)
277 return SoftLong.mul(MathShelf.longUnpackLow(__a),
278 MathShelf.longUnpackHigh(__a));
282 * Ors a value.
284 * @param __al A low.
285 * @param __ah A high.
286 * @param __bl B low.
287 * @param __bh B high.
288 * @return The result.
289 * @since 2019/05/24
291 @SquirrelJMEVendorApi
292 public static long or(int __al, int __ah, int __bl, int __bh)
294 return MathShelf.longPack(__al | __bl, __ah | __bh);
298 * Ors a value.
300 * @param __a A.
301 * @param __b B.
302 * @return The result.
303 * @since 2023/08/02
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.
317 * @param __al A low.
318 * @param __ah A high.
319 * @param __bl B low.
320 * @param __bh B high.
321 * @return The result.
322 * @since 2019/05/24
324 @SquirrelJMEVendorApi
325 public static long rem(int __al, int __ah, int __bl, int __bh)
327 // Dividing by zero?
328 if (__bh == 0 && __bl == 0)
329 throw new ArithmeticException();
331 return SoftLong.__div(true, __al, __ah, __bl, __bh);
335 * Remainders a value.
337 * @param __a A.
338 * @param __b B.
339 * @return The result.
340 * @since 2023/08/02
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.
354 * @param __al A low.
355 * @param __ah A high.
356 * @param __s Shift amount.
357 * @return The result.
358 * @since 2019/05/24
360 @SquirrelJMEVendorApi
361 public static long shl(int __al, int __ah, int __s)
363 // Mask the shift amount
364 __s &= 0x3F;
366 // Doing nothing?
367 if (__s == 0)
368 return MathShelf.longPack(__al, __ah);
370 // Shifting all the low bits to the high bits
371 else if (__s >= 32)
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.
382 * @param __a A.
383 * @param __s Shift amount.
384 * @return The result.
385 * @since 2023/08/02
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.
397 * @param __al A low.
398 * @param __ah A high.
399 * @param __s Shift amount.
400 * @return The result.
401 * @since 2019/05/24
403 @SquirrelJMEVendorApi
404 public static long shr(int __al, int __ah, int __s)
406 // Mask the shift amount
407 __s &= 0x3F;
409 // Doing nothing?
410 if (__s == 0)
411 return MathShelf.longPack(__al, __ah);
413 // Shifting all the high bits low
414 else if (__s >= 32)
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),
420 (__ah >> __s));
424 * Shifts value right by bits.
426 * @param __a A.
427 * @param __s Shift amount.
428 * @return The result.
429 * @since 2023/08/02
431 @SquirrelJMEVendorApi
432 public static long shr(long __a, int __s)
434 return SoftLong.shr(MathShelf.longUnpackLow(__a),
435 MathShelf.longUnpackHigh(__a), __s);
439 * Subtracts values.
441 * @param __al A low.
442 * @param __ah A high.
443 * @param __bl B low.
444 * @param __bh B high.
445 * @return The result.
446 * @since 2019/05/24
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
453 __bh = (~__bh);
454 __bl = (~__bl + 1);
455 if (__bl == 0)
456 __bh++;
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
463 // high part
464 if ((cl + 0x80000000) < (__al + 0x80000000))
465 ch++;
467 // Return result
468 return MathShelf.longPack(cl, ch);
472 * Subtracts values.
474 * @param __a A.
475 * @param __b B.
476 * @return The result.
477 * @since 2023/08/02
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.
494 * @since 2019/05/24
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.
507 * @since 2023/08/02
509 @SquirrelJMEVendorApi
510 public static double toDouble(long __a)
512 return SoftLong.toDouble(MathShelf.longUnpackLow(__a),
513 MathShelf.longUnpackHigh(__a));
517 * Converts to float.
519 * @param __al A low.
520 * @param __ah A high.
521 * @return The result.
522 * @since 2019/05/24
524 @SquirrelJMEVendorApi
525 public static float toFloat(int __al, int __ah)
527 throw Debugging.todo();
531 * Converts to float.
533 * @param __a A value.
534 * @return The result.
535 * @since 2023/08/02
537 @SquirrelJMEVendorApi
538 public static float toFloat(long __a)
540 return SoftLong.toFloat(MathShelf.longUnpackLow(__a),
541 MathShelf.longUnpackHigh(__a));
545 * Converts to integer.
547 * @param __al A low.
548 * @param __ah A high.
549 * @return The result.
550 * @since 2019/05/24
552 @SquirrelJMEVendorApi
553 public static int toInteger(int __al, @SuppressWarnings("unused") int __ah)
555 // Just return the low order bits
556 return __al;
560 * Converts to integer.
562 * @param __a A value.
563 * @return The result.
564 * @since 2023/08/02
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.
576 * @param __al A low.
577 * @param __ah A high.
578 * @param __s Shift amount.
579 * @return The result.
580 * @since 2019/05/24
582 @SquirrelJMEVendorApi
583 public static long ushr(int __al, int __ah, int __s)
585 // Mask the shift amount
586 __s &= 0x3F;
588 // Doing nothing?
589 if (__s == 0)
590 return MathShelf.longPack(__al, __ah);
592 // Shifting all the high bits low
593 else if (__s >= 32)
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),
598 (__ah >>> __s));
602 * Shifts value bits right unsigned.
604 * @param __a A.
605 * @param __s Shift amount.
606 * @return The result.
607 * @since 2023/08/02
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.
619 * @param __al A low.
620 * @param __ah A high.
621 * @param __bl B low.
622 * @param __bh B high.
623 * @return The result.
624 * @since 2019/05/24
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.
635 * @param __a A.
636 * @param __b B.
637 * @return The result.
638 * @since 2023/08/02
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.
658 * @since 2019/05/24
660 @SuppressWarnings("CommentedOutCode")
661 private static long __div(boolean __doRem, int __nl, int __nh,
662 int __dl, int __dh)
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
671 // R := 0
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
676 // if R >= D then
677 // R = R - D
678 // Q(i) := 1
679 // end
680 // end
681 // long qx = 0, rx = 0;
683 // High and low resultant values
684 int ql = 0;
685 int qh = 0;
686 int rl = 0;
687 int rh = 0;
689 // Disallow division by zero
690 if (__dl == 0)
691 return 0;
693 // Results in a negative? Only results in such if either side is
694 // a negative value
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
700 if (negNum)
702 // Negate and check for overflow
703 __nh = (~__nh);
704 __nl = (~__nl + 1);
705 if (__nl == 0)
706 __nh++;
709 // Make the denominator positive, if negative
710 if (negDem)
712 // Negate and check for overflow
713 __dh = (~__dh);
714 __dl = (~__dl + 1);
715 if (__dl == 0)
716 __dh++;
719 // __dl and __dh for unsigned compare
720 int dlUnsigned = __dl + Integer.MIN_VALUE;
721 int dhUnsigned = __dh + Integer.MIN_VALUE;
723 // Perform Math
724 for (int i = 63, hMask = 0xFFFF_FFFF, lMask = 0;
725 i >= 0;
726 i--, hMask >>>= 1, lMask = ((lMask >> 1) | 0x8000_0000))
728 // rx <<= 1;
729 // rx &= 0xFFFFFFFFFFFFFFFEL;
730 rh <<= 1;
731 rh |= (rl >>> 31);
732 rl <<= 1;
734 // rx |= ((__nx >>> i) & 1L); ... only take the lowest bit!
735 // branching:
736 // ! if (i >= 32)
737 // ! rl |= ((__nh >>> (i - 32)) & 0x1);
738 // ! else
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;
750 if (cmp >= 0 &&
751 (cmp > 0 || // Is just a bigger number overall?
752 rl + Integer.MIN_VALUE >= dlUnsigned))
754 // rx -= __dx;
755 // The same as add, but the second operand is negated
756 // Negate and check for overflow
757 int bh = (~__dh);
758 int bl = (~__dl + 1);
759 if (bl == 0)
760 bh++;
762 // Add the higher/lower parts
763 rh = rh + bh;
764 int cl = rl + bl;
766 // If the low addition carried a bit over, then set that bit in
767 // the high part
768 if ((cl + 0x80000000) < (rl + 0x80000000))
769 rh++;
771 // Use result
772 rl = cl;
774 // qx |= (1L << i);
775 if (i >= 32)
776 qh |= (1 << (i - 32));
777 else
778 ql |= (1 << i);
782 // Return the remainder if needed, note the remainder is negative only
783 // if the numerator is negative
784 if (__doRem)
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
795 * negative.
797 * @param __al A low.
798 * @param __ah A high.
799 * @param __bl B low.
800 * @param __bh B high.
801 * @return The result.
802 * @since 2019/05/24
804 private static long __mul(int __al, int __ah, int __bl, int __bh)
806 // First value
807 int a = (__ah >>> 16);
808 int b = (__ah & 0xFFFF);
809 int c = (__al >>> 16);
810 int d = (__al & 0xFFFF);
812 // Second value
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.
822 // | a. b, c. d
823 // * | w. x, y. z
824 // ============|===.===,===.===
825 // |d_w.d_x,d_y.d_z
826 // c_w|c_x.c_y,c_z.
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.
835 int over;
837 // Multiply and add all the parts together
838 // int p = (d * z);
839 int p = (d * z);
840 over = (p >>> 16);
842 // int o = (d * y) + (c * z) + (p >>> 16);
843 int o = over + (d * y);
844 over = (o >>> 16);
845 o = (o & 0xFFFF) + (c * z);
846 over += (o >>> 16);
848 // int n = (d * x) + (c * y) + (b * z) + (o >>> 16);
849 int n = over + (d * x);
850 over = (n >>> 16);
851 n = (n & 0xFFFF) + (c * y);
852 over += (n >>> 16);
853 n = (n & 0xFFFF) + (b * z);
854 over += (n >>> 16);
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
858 // discarded anyway!
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));