2121import de .tilman_neumann .util .Ensure ;
2222
2323/**
24- * An incomplete 128 bit unsigned int implementation.
24+ * An incomplete 128 bit integer implementation.
2525 *
26- * Implementation notes :
27- * * a +Long.MIN_VALUE <> b +Long- MIN_VALUE is an inlined compareUnsigned(a, b ) <> 0.
26+ * Implementation note :
27+ * r_lo +Long.MIN_VALUE < low +Long. MIN_VALUE is an inlined compareUnsigned(r_lo, low ) < 0.
2828 *
2929 * @author Tilman Neumann
3030 */
@@ -51,64 +51,88 @@ public long getLow() {
5151 }
5252
5353 /**
54- * Add two unsigned 128 bit integers.
55- * @param other
56- * @return this + other
54+ * Add two 128 bit integers.
55+ * @param b
56+ * @return this + b
5757 */
58- public Uint128 add_v1 (Uint128 other ) {
59- // We know for sure that low overflows if both low and o_lo are 64 bit. If only one of the input 'low's
60- // is 64 bit, then we can recognize an overflow if the result.lo is not 64 bit.
61- final long o_lo = other .getLow ();
62- final long o_hi = other .getHigh ();
63- final long r_lo = low + o_lo ;
64- long r_hi = high + o_hi ;
65- if ((low <0 && o_lo <0 ) || ((low <0 || o_lo <0 ) && (r_lo >= 0 ))) r_hi ++;
58+ public Uint128 add_v1 (Uint128 b ) {
59+ // We know for sure that low overflows if both low and b_lo are 64 bit. If only one of the input 'low's
60+ // is 64 bit, then we can recognize an overflow if r_lo is not 64 bit.
61+ final long b_lo = b .getLow ();
62+ final long b_hi = b .getHigh ();
63+ final long r_lo = low + b_lo ;
64+ long r_hi = high + b_hi ;
65+ if ((low <0 && b_lo <0 ) || ((low <0 || b_lo <0 ) && (r_lo >= 0 ))) r_hi ++;
6666 return new Uint128 (r_hi , r_lo );
6767 }
6868
6969 /**
70- * Add two unsigned 128 bit integers.
70+ * Add two 128 bit integers.
7171 *
72- * Simpler carry recognition and thus much faster than the first version ,
73- * thanks to Ben, see https://www.mersenneforum.org/showpost.php?p=524300&postcount=173.
72+ * Simpler carry recognition thanks to Ben Buhrow ,
73+ * see https://www.mersenneforum.org/showpost.php?p=524300&postcount=173.
7474 *
75- * @param other
76- * @return this + other
75+ * @param b
76+ * @return this + b
7777 */
78- public Uint128 add /*_v2*/ (Uint128 other ) {
79- long a = low + other .getLow ();
80- long b = high + other .getHigh ();
81- if (a +Long .MIN_VALUE < low +Long .MIN_VALUE ) b ++;
82- return new Uint128 (b , a );
78+ public Uint128 add /*_v2*/ (Uint128 b ) {
79+ long r_lo = low + b .getLow ();
80+ long r_hi = high + b .getHigh ();
81+ if (r_lo +Long .MIN_VALUE < low +Long .MIN_VALUE ) r_hi ++;
82+ return new Uint128 (r_hi , r_lo );
8383 }
8484
8585 /**
86- * Compute the sum of this and other, return the high part.
87- * @param other
88- * @return high part of this + other
86+ * Add two 128 bit integers, AI-generated version.
87+ *
88+ * @param b
89+ * @return this + b
8990 */
90- public long add_getHigh (Uint128 other ) {
91- long a = low + other .getLow ();
92- long b = high + other .getHigh ();
93- return (a +Long .MIN_VALUE < low +Long .MIN_VALUE ) ? b + 1 : b ;
91+ public Uint128 add_v3 (Uint128 b ) {
92+ long r_lo = low + b .getLow ();
93+ long carry = Long .compareUnsigned (r_lo , low ) < 0 ? 1 : 0 ;
94+ long r_hi = high + b .getHigh () + carry ;
95+ return new Uint128 (r_hi , r_lo );
96+ }
97+
98+ /**
99+ * Add two 128 bit integers, return the high part.
100+ * @param b
101+ * @return high part of this + b
102+ */
103+ public long add_getHigh (Uint128 b ) {
104+ long r_lo = low + b .getLow ();
105+ long r_hi = high + b .getHigh ();
106+ return r_lo +Long .MIN_VALUE < low +Long .MIN_VALUE ? r_hi + 1 : r_hi ;
94107 }
95108
96109 /**
97- * Subtract two unsigned 128 bit integers.
110+ * Subtract two 128 bit integers.
98111 *
99- * @param other
100- * @return this - other
112+ * @param b
113+ * @return this - b, may be negative
101114 */
102- // XXX experimental, probably wrong...
103- public Uint128 subtract (Uint128 other ) {
104- long r_lo = low - other .getLow ();
105- long r_hi = high - other .getHigh ();
106- // check for underflow of low 64 bits, subtract carry to high
107- if (Long .compareUnsigned (r_lo , low ) > 0 ) {
108- --r_hi ;
109- }
115+ public Uint128 subtract (Uint128 b ) {
116+ long b_lo = b .getLow ();
117+ long r_lo = low - b_lo ;
118+ long r_hi = high - b .getHigh ();
119+ if (Long .compareUnsigned (low , b_lo ) < 0 ) --r_hi ;
110120 return new Uint128 (r_hi , r_lo );
111121 }
122+
123+ /**
124+ * Subtract two 128 bit integers. AI-generated version.
125+ *
126+ * @param b
127+ * @return this - b, may be negative
128+ */
129+ public Uint128 subtract_v2 (Uint128 b ) {
130+ long b_lo = b .getLow ();
131+ long r_lo = low - b_lo ;
132+ long borrow = Long .compareUnsigned (low , b_lo ) < 0 ? 1 : 0 ;
133+ long r_hi = high - b .getHigh () - borrow ;
134+ return new Uint128 (r_hi , r_lo );
135+ }
112136
113137 /**
114138 * Multiplication of unsigned 63 bit integers,
@@ -547,17 +571,48 @@ public long and(long other) {
547571 public double doubleValue () {
548572 return toBigInteger ().doubleValue (); // TODO more efficient solution
549573 }
574+
575+ public double doubleValueUnsigned () {
576+ return toBigIntegerUnsigned ().doubleValue (); // TODO more efficient solution
577+ }
550578
551579 /**
552- * Convert this to BigInteger.
553- * @return this unsigned 128 bit integer converted to BigInteger
580+ * Signed conversion to BigInteger.
581+ * @return this as a signed 127 bit integer converted to BigInteger
554582 */
555583 public BigInteger toBigInteger () {
556- return new BigInteger (Long .toBinaryString (high ), 2 ).shiftLeft (64 ).add (new BigInteger (Long .toBinaryString (low ), 2 ));
584+ return BigInteger .valueOf (high ).shiftLeft (64 ).or (toBigIntegerUnsigned (low ));
585+ }
586+
587+ /**
588+ * Unsigned conversion to BigInteger.
589+ * @return this as an unsigned 128 bit integer converted to BigInteger
590+ */
591+ public BigInteger toBigIntegerUnsigned () {
592+ return toBigIntegerUnsigned (high ).shiftLeft (64 ).or (toBigIntegerUnsigned (low ));
593+ }
594+
595+ // helper method
596+ private static BigInteger toBigIntegerUnsigned (long n ) {
597+ BigInteger big = BigInteger .valueOf (n & Long .MAX_VALUE ); // drop sign bit
598+ if (n < 0 ) {
599+ big = big .setBit (63 ); // now big is unsigned 64 bit
600+ }
601+ return big ;
557602 }
558603
604+ /**
605+ * @return a string representing this as a signed integer
606+ */
559607 @ Override
560608 public String toString () {
561- return toBigInteger ().toString ();
609+ return toBigInteger ().toString (); // TODO more efficient solution
610+ }
611+
612+ /**
613+ * @return a string representing this as an unsigned integer
614+ */
615+ public String toStringUnsigned () {
616+ return toBigIntegerUnsigned ().toString (); // TODO more efficient solution
562617 }
563618}
0 commit comments