1+ package unsigned
2+
3+ import java.math.BigInteger
4+
5+
6+ fun Long.toUnsignedString (radix : Int = 10): String =
7+ if (this >= 0 )
8+ toString(radix)
9+ else
10+ when (radix) {
11+ 2 -> toBinaryString()
12+
13+ 4 -> toUnsignedString0(2 )
14+
15+ 8 -> toOctalString()
16+
17+ 10 -> {
18+ /*
19+ * We can get the effect of an unsigned division by 10
20+ * on a long value by first shifting right, yielding a
21+ * positive value, and then dividing by 5. This
22+ * allows the last digit and preceding digits to be
23+ * isolated more quickly than by an initial conversion
24+ * to BigInteger.
25+ */
26+ val quot = this .ushr(1 ) / 5
27+ val rem = this - quot * 10
28+ quot.toString_() + rem
29+ }
30+
31+ 16 -> toHexString()
32+
33+ 32 -> toUnsignedString0(5 )
34+
35+ else -> toUnsignedBigInteger().toString(radix)
36+ }
37+
38+ fun Long.toString (radix : Int ): String {
39+ var i = this
40+ var _radix = radix
41+ if (_radix < Character .MIN_RADIX || _radix > Character .MAX_RADIX )
42+ _radix = 10
43+ if (_radix == 10 )
44+ return toString_()
45+ val buf = CharArray (65 )
46+ var charPos = 64
47+ val negative = i < 0
48+
49+ if (! negative) {
50+ i = - i
51+ }
52+
53+ while (i <= - _radix ) {
54+ buf[charPos-- ] = digits[(- (i % _radix )).toInt()]
55+ i = i / _radix
56+ }
57+ buf[charPos] = digits[(- i).toInt()]
58+
59+ if (negative) {
60+ buf[-- charPos] = ' -'
61+ }
62+
63+ return String (buf, charPos, 65 - charPos)
64+ }
65+
66+ fun Long.toString_ (): String {
67+ if (this == java.lang.Long .MIN_VALUE )
68+ return " -9223372036854775808"
69+ val size = if (this < 0 ) stringSize(- this ) + 1 else stringSize(this )
70+ val buf = CharArray (size)
71+ getChars(this , size, buf)
72+ return String (buf)
73+ }
74+
75+ internal fun stringSize (x : Long ): Int {
76+ var p = 10L
77+ for (i in 1 .. 18 ) {
78+ if (x < p)
79+ return i
80+ p * = 10
81+ }
82+ return 19
83+ }
84+
85+ internal fun getChars (i : Long , index : Int , buf : CharArray ) {
86+ var _i = i
87+ var q: Long
88+ var r: Int
89+ var charPos = index
90+ var sign: Char = 0 .toChar()
91+
92+ if (_i < 0 ) {
93+ sign = ' -'
94+ _i = - _i
95+ }
96+
97+ // Get 2 digits/iteration using longs until quotient fits into an int
98+ while (_i > Integer .MAX_VALUE ) {
99+ q = _i / 100
100+ // really: r = i - (q * 100);
101+ r = (_i - ((q shl 6 ) + (q shl 5 ) + (q shl 2 ))).toInt()
102+ _i = q
103+ buf[-- charPos] = DigitOnes [r]
104+ buf[-- charPos] = DigitTens [r]
105+ }
106+
107+ // Get 2 digits/iteration using ints
108+ var q2: Int
109+ var i2 = _i .toInt()
110+ while (i2 >= 65536 ) {
111+ q2 = i2 / 100
112+ // really: r = i2 - (q * 100);
113+ r = i2 - ((q2 shl 6 ) + (q2 shl 5 ) + (q2 shl 2 ))
114+ i2 = q2
115+ buf[-- charPos] = DigitOnes [r]
116+ buf[-- charPos] = DigitTens [r]
117+ }
118+
119+ // Fall thru to fast mode for smaller numbers
120+ // assert(i2 <= 65536, i2);
121+ while (true ) {
122+ q2 = (i2 * 52429 ).ushr(16 + 3 )
123+ r = i2 - ((q2 shl 3 ) + (q2 shl 1 )) // r = i2-(q2*10) ...
124+ buf[-- charPos] = digits[r]
125+ i2 = q2
126+ if (i2 == 0 ) break
127+ }
128+ if (sign.toInt() != 0 )
129+ buf[-- charPos] = sign
130+ }
131+
132+ internal val DigitTens by lazy {
133+ charArrayOf(
134+ ' 0' , ' 0' , ' 0' , ' 0' , ' 0' , ' 0' , ' 0' , ' 0' , ' 0' , ' 0' ,
135+ ' 1' , ' 1' , ' 1' , ' 1' , ' 1' , ' 1' , ' 1' , ' 1' , ' 1' , ' 1' ,
136+ ' 2' , ' 2' , ' 2' , ' 2' , ' 2' , ' 2' , ' 2' , ' 2' , ' 2' , ' 2' ,
137+ ' 3' , ' 3' , ' 3' , ' 3' , ' 3' , ' 3' , ' 3' , ' 3' , ' 3' , ' 3' ,
138+ ' 4' , ' 4' , ' 4' , ' 4' , ' 4' , ' 4' , ' 4' , ' 4' , ' 4' , ' 4' ,
139+ ' 5' , ' 5' , ' 5' , ' 5' , ' 5' , ' 5' , ' 5' , ' 5' , ' 5' , ' 5' ,
140+ ' 6' , ' 6' , ' 6' , ' 6' , ' 6' , ' 6' , ' 6' , ' 6' , ' 6' , ' 6' ,
141+ ' 7' , ' 7' , ' 7' , ' 7' , ' 7' , ' 7' , ' 7' , ' 7' , ' 7' , ' 7' ,
142+ ' 8' , ' 8' , ' 8' , ' 8' , ' 8' , ' 8' , ' 8' , ' 8' , ' 8' , ' 8' ,
143+ ' 9' , ' 9' , ' 9' , ' 9' , ' 9' , ' 9' , ' 9' , ' 9' , ' 9' , ' 9' )
144+ }
145+
146+ internal val DigitOnes by lazy {
147+ charArrayOf(
148+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
149+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
150+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
151+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
152+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
153+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
154+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
155+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
156+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ,
157+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' )
158+ }
159+
160+ internal val digits by lazy {
161+ charArrayOf(
162+ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' ,
163+ ' 6' , ' 7' , ' 8' , ' 9' , ' a' , ' b' ,
164+ ' c' , ' d' , ' e' , ' f' , ' g' , ' h' ,
165+ ' i' , ' j' , ' k' , ' l' , ' m' , ' n' ,
166+ ' o' , ' p' , ' q' , ' r' , ' s' , ' t' ,
167+ ' u' , ' v' , ' w' , ' x' , ' y' , ' z' )
168+ }
169+
170+ fun Long.toBinaryString () = toUnsignedString0(1 )
171+
172+ internal fun Long.toUnsignedString0 (shift : Int ): String {
173+ // assert shift > 0 && shift <=5 : "Illegal shift value";
174+ val mag = java.lang.Long .SIZE - java.lang.Long .numberOfLeadingZeros(this )
175+ val chars = Math .max((mag + (shift - 1 )) / shift, 1 )
176+ val buf = CharArray (chars)
177+
178+ formatUnsignedLong(shift, buf, 0 , chars)
179+ return String (buf)
180+ }
181+
182+ internal fun Long.formatUnsignedLong (shift : Int , buf : CharArray , offset : Int , len : Int ): Int {
183+ var _this = this
184+ var charPos = len
185+ val radix = 1 shl shift
186+ val mask = radix - 1
187+ do {
188+ buf[offset + -- charPos] = digits[toInt() and mask]
189+ _this = _this ushr shift
190+ } while (_this != 0L && charPos > 0 )
191+
192+ return charPos
193+ }
194+
195+ fun Long.toOctalString () = toUnsignedString0(3 )
196+
197+ fun Long.toHexString () = toUnsignedString0(4 )
198+
199+ private fun Long.toUnsignedBigInteger (): BigInteger {
200+ if (this >= 0L )
201+ return BigInteger .valueOf(this )
202+ else {
203+ val upper = this .ushr(32 ).toInt()
204+ val lower = this .toInt()
205+
206+ // return (upper << 32) + lower
207+ return BigInteger .valueOf(Integer .toUnsignedLong(upper)).shiftLeft(32 ).add(BigInteger .valueOf(Integer .toUnsignedLong(lower)))
208+ }
209+ }
0 commit comments