How does Integer.toString() works internally? - java

I found that a similar question has been asked before here : how does Float.toString() and Integer.toString() works?
But this doesn't speak about how that function internally works. When I opened the internally source code of Integer.toString(), it is not understandable for normal junior java programmer.
Can somebody please explain what happens internally in short description ?
NOTE : This was one of the interview questions that I was asked recently. I had no idea about how to answer such question !

The no arg call of integer.toString() simply calls the static method Integer.toString(int i) (using the integer variables own primitive value), which is implemented as below;
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(0, size, buf);
}
First it checks whether it's value is == the lowest possible integer, and returns that if it is equal. If not, then it checks what size the String needs to be using the stringSize() method of Integer to use as the size of an array of characters.
stringSize() implementation below;
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
Once it has a char[] of the correct size, it then populates that array using the getChars() method, implemented below;
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Generate two digits per iteration
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r];
i = q;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
}
}
Explaining each individual step would take far too long for for a stackoverflow answer. The most pertinent section however (as pointed out in the comments) is the getChars() method which, complicated bit shifting aside, is essentially process of elimination for finding each character. I am afraid I can't go into any greater detail than that without going beyond my own understanding.

Related

How to put numbers to array in while loop in java?

I am trying to add two binary numbers and then get their sum in binary system. I got their sum in decimal and now I am trying to turn it into binary. But there is problem that when I take their sum (in decimal) and divide by 2 and find remainders(in while loop), I need to put remainders into array in order print its reverse. However, there is an error in array part. Do you have any suggestions with my code? Thanks in advance.
Here is my code:
import java.util.Scanner;
public class ex1 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
int k = dec1(n)+dec2(m);
int i=0,c;
int[] arr= {};
while(k>0) {
c = k % 2;
k = k / 2;
arr[i++]=c; //The problem is here. It shows some //error
}
while (i >= 0) {
System.out.print(arr[i--]);
}
}
public static int dec1(int n) {
int a,i=0;
int dec1 = 0;
while(n>0) {
a=n%10;
n=n/10;
dec1= dec1 + (int) (a * Math.pow(2, i));
i++;
}
return dec1;
}
public static int dec2(int m) {
int b,j=0;
int dec2 = 0;
while(m>0) {
b=m%10;
m=m/10;
dec2= dec2 + (int) (b * Math.pow(2, j));
j++;
}
return dec2;
}
}
Here:
int[] arr= {};
creates an empty array. Arrays don't grow dynamically in Java. So any attempt to access any index of arr will result in an ArrayIndexOutOfBounds exception. Because empty arrays have no "index in bounds" at all.
So:
first ask the user for the count of numbers he wants to enter
then go like: int[] arr = new int[targetCountProvidedByUser];
The "more" real answer would be to use List<Integer> numbersFromUsers = new ArrayList<>(); as such Collection classes allow for dynamic adding/removing of elements. But for a Java newbie, you better learn how to deal with arrays first.
Why are you using two different methods to do the same conversion? All you need is one.
You could have done this in the main method.
int k = dec1(n)+dec1(m);
Instead of using Math.pow which returns a double and needs to be cast, another alternative is the following:
int dec = 0;
int mult = 1;
int bin = 10110110; // 128 + 48 + 6 = 182.
while (bin > 0) {
// get the right most bit
int bit = (bin % 10);
// validate
if (bit < 0 || bit > 1) {
throw new IllegalArgumentException("Not a binary number");
}
// Sum up each product, multiplied by a running power of 2.
// this is required since bits are taken from the right.
dec = dec + mult * bit;
bin /= 10;
mult *= 2; // next power of 2
}
System.out.println(dec); // prints 182
An alternative to that is to use a String to represent the binary number and take the bits from the left (high order position).
String bin1 = "10110110";
int dec1 = 0;
// Iterate over the characters, left to right (high to low)
for (char b : bin1.toCharArray()) {
// convert to a integer by subtracting off character '0'.
int bit = b - '0';
// validate
if (bit < 0 || bit > 1) {
throw new IllegalArgumentException("Not a binary number");
}
// going left to right, first multiply by 2 and then add the bit
// Each time thru, the sum will be multiplied by 2 which shifts everything left
// one bit.
dec1 = dec1 * 2 + bit;
}
System.out.println(dec1); // prints 182
One possible way to display the result in binary is to use a StringBuilder and simply insert the converted bits to characters.
public static String toBin(int dec) {
StringBuilder sb = new StringBuilder();
while (dec > 0) {
// by inserting at 0, the bits end up in
// correct order. Adding '0' to the low order
// bit of dec converts to a character.
sb.insert(0, (char) ((dec & 1) + '0'));
// shift right for next bit to convert.
dec >>= 1;
}
return sb.toString();
}

Java integer overflow

I'm totally new to Java and I'm implementing a simple function to convert string to integer on Leetcode.
public int myAtoi(String str) {
if(str.length() == 0){
return 0;
}
str = str.trim();
int n = str.length();
int signal = 0;
if(n == 1 && str.equals("+") || str.equals("-")){
return 0;
}
if(str.charAt(0) == '+'){
signal = 1;
}else if(str.charAt(0) == '-'){
signal = -1;
}
int i = (signal != 0)? 1 : 0;
if(signal == 0){
signal = 1;//default
}
int res = 0;
while(i < n){
char c = str.charAt(i);
if(!Character.isDigit(c)){
return res * signal;
}
//res = res * 10 + c - '0';
if(signal * res > Integer.MAX_VALUE){
return Integer.MAX_VALUE;
}
if(signal * res < Integer.MIN_VALUE){
return Integer.MIN_VALUE;
}
res = res * 10 + c - '0';
++i;
}
return res * signal;
}
I know java integer has the MAX_VALUE of 2147483647. When my input is 2147483648 the output should be 2147483647 but indeed it's -214748648. I really have no idea what's wrong in here. Can anybody help me to understand this?
Consider this example
public static void main(String args[]) {
int i=2147483647;
System.out.println("i="+i);
int j=++i;
System.out.println("Now i is="+i);
System.out.println("j="+j);
}
What happens?
output will be :
i = 2147483647
Now i is=-2147483648
j=-2147483648
The maximum value of integer is 2,147,483,647 and the minimum value is -2,147,483,648. Here in j (with post increment of i), we have crossed the maximum limit of an integer
This is exactly what is happening in your case too .
Because the integer overflows. When it overflows, the next value is Integer.MIN_VALUE
Why?
Integer values are represented in binary form, and there is binary addition in java. It uses a representation called two's complement, in which the first bit of the number represents its sign. Whenever you add 1 to the largest Integer(MAX INT), which has a bit sign of 0, then its bit sign becomes 1 and the number becomes negative.
So, don't put > MAX INT as input, else put a condition in your code to check it on input itself.
The input is never +2147483648 since that value can't be represented as a Java int.
It will wrap around to the negative number you observe, so accounting for that result.

How to save a large array of 5 bit numbers in Java?

How to efficiently save and access a large array of 5 bit numbers in memory?
For example
01100
01101
01110
01111
10000
10001
which I will later convert to a byte to check what number it is?
I was thinking of just using an array of bytes but after a while this will be wasting a lot of memory as this will be a continually growing array. Also I will want to save this array efficiently. I will only be using exactly 5 bits.
This is the code that I use for a bit array implementation in C, in JAVA it's going to be the same, I must reconsider what I said about the list, maybe an array is going to be better.
Anyway, you consider the array as a contiguous segments of bits. Those functions set, get, and read the k-th bit of the array. In this case I'm using an array of integers, so you see '32', is you use an array of bytes, then you'd use '8'.
void set_bit(int a[], int k)
{
int i = k / 32;
int pos = k % 32;
unsigned int flag = 1; // flag = 0000....00001
flag = flag << pos; // flag = 0000...00100..0000
a[i] = a[i] | flag; // set the bit at the k-th position in a[i]
}
void clear_bit(int a[], int k)
{
int i = k / 32;
int pos = k % 32;
unsigned int flag = 1; // flag = 0000....00001
flag = flag << pos; // flag = 0000...00100..0000
flag = ~flag;
a[i] = a[i] & flag; // set the bit at the k-th position in a[i]
}
int test_bit(int a[], int k)
{
int i = k / 32;
int pos = k % 32;
unsigned int flag = 1; // flag = 0000....00001
flag = flag << pos; // flag = 0000...00100..0000
if (a[i] & flag) // test the k-th bit of a to be 1
return 1;
else
return 0;
}
I don't know how you store the five bits number, you'll have to insert them bit by bit, and also keep track of the last empty position in the bit array.
"I was thinking of just using an array of bytes but after a while this will be wasting a lot of memory as this will be a continually growing array."
I've dealt with a similar problem and decided to write a file based BitInputStream and a BitOutputSteam. Therefore running out of memory was no longer an issue. Please note that the given links are not my work but good examples of how to write a bit input/output stream.
I wrote an implementation of a 5-bit byte vector on top of an 8-bit byte vector in Javascript some time ago that might be of some help.
const ByteVector = require('bytevector');
class FiveBuffer {
constructor(buffer = [0], bitsAvailable = 8) {
this.buf = new ByteVector(buffer);
this.bitsAvailable = bitsAvailable;
this.size = Math.floor(((this.byteSize() * 8) - this.bitsAvailable) / 5);
}
push(num) {
if (num > 31 || num < 0)
throw new Error(`Only 5-bit unsigned integers (${num} not among them) are accepted`);
var firstShift = 5 - this.bitsAvailable;
var secondShift = this.bitsAvailable + 3;
var firstShifted = shiftRight(num, firstShift);
var backIdx = this.buf.length - 1;
var back = this.buf.get(backIdx);
this.buf.set(backIdx, back | firstShifted);
if (secondShift < 8) {
var secondShifted = num << secondShift;
this.buf.push(secondShifted);
}
this.bitsAvailable = secondShift % 8;
this.size++;
}
get(idx) {
if (idx > this.size)
throw new Error(`Index ${idx} is out of bounds for FiveBuffer of size ${this.size}`);
var bitIdx = idx * 5;
var byteIdx = Math.floor(bitIdx / 8);
var byte = this.buf.get(byteIdx);
var bit = bitIdx % 8;
var firstShift = 3 - bit;
var firstShifted = shiftRightDestroy(byte, firstShift);
var final = firstShifted;
var secondShift = 11 - bit;
if (secondShift < 8) {
var secondShifted = this.buf.get(byteIdx + 1) >> secondShift;
final = final | secondShifted;
}
return final;
}
buffer() {
this.buf.shrink_to_fit();
return this.buf.buffer();
}
debug() {
var arr = [];
this.buffer().forEach(x => arr.push(x.toString(2)));
console.log(arr);
}
byteSize() {
return this.buf.size();
}
}
function shiftRightDestroy(num, bits) {
var left = 3 - bits;
var res = (left > 0) ? ((num << left) % 256) >> left : num;
return shiftRight(res, bits);
}
function shiftRight(num, bits) {
return (bits < 0) ?
num << -bits :
num >> bits;
}
module.exports = FiveBuffer;

Efficient Parsing of Byte Array to Number

Rather than parsing a byte array to an ASCII string then converting the string to say an integer, it should be more efficient to parse the byte array directly to an integer.
byte[] token = "24000".getBytes(Charset.forName("US-ASCII"));
The following code can do this:
int n = 0;
for (byte b : token)
n = 10*n + (b-'0');
Versus the common approach:
int n = Integer.parseInt(new String(token));
Ref: Dave's answer here >> Converting US-ASCII encoded byte to integer and back
Is there a comprehensive solution that skips String creation and goes straight to result?
Please stop marking the question for closing due to this question:
Convert a byte array to integer in java and vice versa
It deals with non-encoded bytes.
It does not answer my question.
The Java library doesn't seem to have a dedicated tool for the job, but it sure has enough tools to write one yourself.
In my opinion, if you're worried about performance since turning byte arrays to ints is a bottleneck in your code, then I suggest writing your own solution based on the piece of code you provided. If it isn't, then just use parseInt for easier readability.
In any case, if Java had a tool for doing this, it would use pretty much the same code under the hood. That's pretty much what Integer.parseInt() does (except it covers other bases, negative numbers, and is safer):
public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}

How can this Java algorithm be faster

I have this loop which splits a Boolean LinkedList by 8 bits and return the ASCII value of each byte in a buffer. The function return the string buffer.
This code is extremely slow if the LinkedList's size is big. I try to change the Iterator with a simple looping, but it's still slow.
How can this algorithm be really fast ? Maybe with multi-threading ?
Note: The size of the linkedList is not always divisible by 8.
public String toString(){
String buffer = "";
String output = "";
LinkedList<Boolean> bits = this.bits;
for(Iterator it = this.bits.iterator(); it.hasNext();){
if(buffer.length() >= 8){
output += (char)Integer.parseInt(buffer, 2);
buffer = "";
}
buffer += ((Boolean)it.next() == false) ? "0" : "1";
}
if(buffer != "")
output += (char)Integer.parseInt(buffer, 2);
return output;
}
These suggestions will give you enough performance still keeping the code simple and readable. First test using these changes and if doesn't meet your performance requirements then slowly introduce optimization techniques suggested in other answers
Use BitSet instead of LinkedList<Boolean>
use StringBuilder output; instead of String output;
use StringBuilder buffer; instead of String buffer;
Use Integer.valueOf() instead of Integer.parseInt. valueOf uses cache for values below 128 i think.
Use StringBuilder initialized with expected capacity for output:
StringBuilder out = new StringBuilder(bits.size() / 8 + 1);
Use bitwise operations instead of parseInt(), something like this:
int i = 0;
int c = 0;
for(Boolean b: bits){
if (i > 0 && i % 8 == 0){
out.append((char) c);
c = 0;
}
c = (c << 1) | (b ? 1 : 0);
i++;
}
out.append((char) c); // Not sure about the desired behaviour here
String concatenation is slow especially for large lists (since strings are immutable they have to be copied around which takes some time and each copy requires more space as well). Use a StringBuilder instead of a String to append to. In other words: buffer and output should be StringBuilder instances.
As others suggested - use BitSet. For the rest, I think the method below is pretty efficient:
public String toString() {
char[] bytes = new char[bits.size() / 8 + ((bits.size() % 8 > 0) ? 1 : 0)];
int bitCounter = 0;
int word = 0;
int byteCounter = 0;
for (boolean b : bits) {
word = (word << 1) | (b ? 1 : 0);
if (bitCounter == 7) {
bytes[byteCounter] = (char) word;
++byteCounter;
bitCounter = 0;
word = 0;
} else {
++bitCounter;
} // else
} // foreach
bytes[byteCounter] = (char) word;
return new String(bytes);
} // toString() method
Here is possibly a better alternative that does not use byte counter:
public String toString() {
int size = bits.size() / 8 + ((bits.size() % 8 > 0) ? 1 : 0);
if (size == 0) {
return "";
} // if
char[] bytes = new char[size];
int bitCounter = 0;
int word = 0;
for (boolean b : bits) {
if (bitCounter % 8 == 0
&& bitCounter > 0) {
bytes[(bitCounter - 1) / 8] = (char) word;
word = 0;
} // if
word = (word << 1) | (b ? 1 : 0);
++bitCounter;
} // foreach
bytes[size - 1] = (char) word;
return new String(bytes);
} // toString() method
Try to keep buffer as an int. I mean
buffer = buffer << 1 + (((Boolean)it.next() == false) ? 0 : 1);
instead of
buffer += ((Boolean)it.next() == false) ? "0" : "1";
Also use StringBuilder for output. This is a small change here but always a bit.
Try the following:
StringBuilder b = new StringBuilder();
int ch = 0;
int n = 0;
for (Boolean bit : bits) {
ch <<= 1;
if (bit) {
ch++;
}
if (++n == 8) {
b.append((char)ch);
n = 0;
ch = 0;
}
}
if (n > 0) {
b.append((char)ch);
}
System.out.println(b.toString());
Use StringBuffer or stringBuilder instead of String for your buffer and output vars.
String vars are immutable, so every operations creates a new instance in heap, while StringBuilder and StringBuffer are not.

Categories