krakatoa
asked on
Return value from Integer.toBinaryString().
Can I just double-check this please :
Integer.toBinaryString(int i)
returns an unsigned string version of the binary of the int.
My question is - how does this marry with the two's complement prescription, that a 1 in the MSB indicates a negative value? (.toBinaryString(200) for example returns 11001000).
ASKER
For decimal 2147483647 toBinaryString returns :
11111111111111111111111111 11111
. . . and for decimal -2147483648 :
10000000000000000000000000 000000
11111111111111111111111111
. . . and for decimal -2147483648 :
10000000000000000000000000
Yes, so you can see from the latter that 2's complement is being used
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Yeah I agree - it's odd that there's not an option to include the leading zeros if you want.
You may want to explore:
https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#numberOfLeadingZeros-int-
which returns the number of leading zeros.
Or you could use String format to fix this up:
You may want to explore:
https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#numberOfLeadingZeros-int-
which returns the number of leading zeros.
Or you could use String format to fix this up:
private String convertToBinary(int value) {
int length = 32 ;
String binary = String.format("%" + length + "s", Integer.toBinaryString(value)).replace(' ', '0');
return binary ;
}
Decimal 64 is 00000000000000000000000001000000
Decimal 123 is 00000000000000000000000001111011
Decimal -1 is 11111111111111111111111111111111
Decimal 1 is 00000000000000000000000000000001
Yes indeed. I wrote my own toBinaryString/toHexString routines, what must be, by now, decades ago, for this reason
If you peek inside the JDK - you can actually see the moment where this happens:
If they had skipped that step or made it optional, you'd get what you want.
But formatUnsignedInt() is a private method - no way to just call to it.
public static String toBinaryString(int i) {
return toUnsignedString0(i, 1);
}
/**
* Convert the integer to an unsigned number.
*/
private static String toUnsignedString0(int val, int shift) {
// assert shift > 0 && shift <=5 : "Illegal shift value";
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
int chars = Math.max(((mag + (shift - 1)) / shift), 1); // CUT OFF THE LEADING ZEROS
if (COMPACT_STRINGS) {
byte[] buf = new byte[chars];
formatUnsignedInt(val, shift, buf, chars);
return new String(buf, LATIN1);
If they had skipped that step or made it optional, you'd get what you want.
But formatUnsignedInt() is a private method - no way to just call to it.
ASKER
Thnx both.
Well I'm looking to find a way to include negative numbers in this piece of code (which works fine for positives). (Of course it won't even enter the loop, when fed a negative decimal, but attempts made to get around that have also failed)
I'm wondering if I'm overlooking something simpler that I've missed in my approach. /)
Well I'm looking to find a way to include negative numbers in this piece of code (which works fine for positives). (Of course it won't even enter the loop, when fed a negative decimal, but attempts made to get around that have also failed)
I'm wondering if I'm overlooking something simpler that I've missed in my approach. /)
class ToBinary {
static StringBuilder binaryString;
static int decimal;
static int remainder;
public static void main(String[] args){
decimal = Integer.valueOf(args[0]).intValue();
binaryString = new StringBuilder();
while(decimal>0){
remainder = (decimal - ((decimal/2)*2));
binaryString.append(Integer.toString(remainder));
decimal /=2;
}
System.out.println("\nHomemade calc ...");
System.out.println(binaryString.reverse().toString());
System.out.println("\n.toBinaryString() calc ...");
System.out.println(Integer.toBinaryString(Integer.valueOf(args[0])));
}
}
ASKER
Doug - Just missed your last. Dealing tomo . . . late here. Thnx.
Maybe I should have posted a bit more too, since this is how the JDK does what you're working on:
This writes to a byte[] buf, but could just as easily be appending to a StringBuffer.
Doug
/**
* Format an {@code int} (treated as unsigned) into a byte buffer (LATIN1 version). If
* {@code len} exceeds the formatted ASCII representation of {@code val},
* {@code buf} will be padded with leading zeroes.
*
* @param val the unsigned int to format
* @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary) // NOTE: Just 1 for binary here
* @param buf the byte buffer to write to
* @param len the number of characters to write
*/
private static void formatUnsignedInt(int val, int shift, byte[] buf, int len) {
int charPos = len;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[--charPos] = (byte)Integer.digits[val & mask];
val >>>= shift;
} while (charPos > 0);
}
/**
* All possible chars for representing a number as a String
*/
static final char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};
This writes to a byte[] buf, but could just as easily be appending to a StringBuffer.
Doug
ASKER
Long and Widening Road . . . . but . . . . . . I'm still on it.
ASKER
I'm still rummaging around in the long grass on this . . . but before I get back properly with an additional point or two, I wanted to see what you thought of this contribution to the science :
Binary Addition Example
Obtaining 38 as the result there is obviously correct when as demonstrated, 0011010 is added to 0001100. But applying that very same method when adding 39 to 51 (binary 100111 and 110011) will not be correct, giving 88 (1011000b) as an answer, instead of the correct 90 (1011010b).
When there's a carry, and the present bits are both set to 1s, the exercise at that index should be a retained 1 bit, plus a further 1 carry to the next index point. That's where they've lost the 2 difference between 88 ad 90. Isn't it ?
Binary Addition Example
Obtaining 38 as the result there is obviously correct when as demonstrated, 0011010 is added to 0001100. But applying that very same method when adding 39 to 51 (binary 100111 and 110011) will not be correct, giving 88 (1011000b) as an answer, instead of the correct 90 (1011010b).
When there's a carry, and the present bits are both set to 1s, the exercise at that index should be a retained 1 bit, plus a further 1 carry to the next index point. That's where they've lost the 2 difference between 88 ad 90. Isn't it ?
And given that binary arithmetic is nearly always being done on numbers with a fixed size (number of bits) what to do about the carry when it exceeds the space is an endless challenge.
Hence the whole series of bugs around "add 1" to 255 and result is -127.
I wonder how many early rockets blew up because of that one :)
ASKER
Great comment there Doug, i.i.m.s.s. ;)
But the way they've explained it on that link leaves a kind of unexplained "ghost logic", which you have to figure out without any further help from the example.
The only way that this works for someone like me is to re-write the truth table to become :
1 + 1 = 0 carry 1
1+1+1 = 1 carry 1
1+0 = 1
0+1 = 1
0+0 = 0
Which - for me - is about a million times easier to follow.
But the way they've explained it on that link leaves a kind of unexplained "ghost logic", which you have to figure out without any further help from the example.
The only way that this works for someone like me is to re-write the truth table to become :
1 + 1 = 0 carry 1
1+1+1 = 1 carry 1
1+0 = 1
0+1 = 1
0+0 = 0
Which - for me - is about a million times easier to follow.
ASKER
I decided to try converting any in-range denary int to binary, by way of dealing with the ten's position each time, then adding them together. Quite a bit of fun. Only works for positive ints, this code.
class DecToBin {
static int originalDecimal;
static int currentDecimal;
static int remainder ;
static int amountToDealWith ;
static int multiplier;
static int position=0;
static int indexPointValue = 0;
static int carry = 0;
static String originalInBinary;
public static void main(String[] args){
originalDecimal = Integer.valueOf(args[0]).intValue();
if(originalDecimal<10||originalDecimal%2==0){originalInBinary = String.format("%0" + ((int)Math.ceil(Math.log10(originalDecimal)/Math.log10(2))+1) + "d", 0);}
else{originalInBinary = String.format("%0" + ((int)Math.ceil(Math.log10(originalDecimal)/Math.log10(2))) + "d", 0);}
currentDecimal = originalDecimal;
remainder = originalDecimal;
StringBuilder thisString = new StringBuilder(originalInBinary);
StringBuilder accumulator = new StringBuilder(originalInBinary); //My end value container.
while(remainder>0){
multiplier = (int) ((currentDecimal / (int)(Math.pow(10,(int)Math.log10(currentDecimal)))));
remainder = (int)(currentDecimal % Math.pow(10,(int)Math.log10(currentDecimal)));
amountToDealWith = multiplier*((int)Math.pow(10,(int)Math.log10(currentDecimal))) ;
currentDecimal = remainder ;
while(amountToDealWith>0){
position = (int)(Math.log10(amountToDealWith)/Math.log10(2));
thisString.setCharAt(position, '1');
amountToDealWith -= (int)Math.pow(2, position);
}
thisString.reverse(); // Correct the endianness.
for(int d = originalInBinary.length()-1;d>-1;d--){ //Add the present binary part to the overall accumulation.
indexPointValue = ((Character.getNumericValue(thisString.charAt(d))) + ((Character.getNumericValue(accumulator.charAt(d))))) + carry ;
switch (indexPointValue) {
case 0 : accumulator.setCharAt(d,'0') ;
carry = 0 ;
break;
case 1 : accumulator.setCharAt(d,'1') ;
carry = 0 ;
break;
case 2 : accumulator.setCharAt(d,'0') ;
carry = 1 ;
break;
case 3 : accumulator.setCharAt(d,'1') ;
carry = 1 ;
break;
}
}
thisString = new StringBuilder(originalInBinary); // Reset to all zeros.
} //End main algo.
if(accumulator.charAt(0)=='0'){accumulator.deleteCharAt(0);}
System.out.println(originalDecimal+" in binary by this code is "+accumulator.toString());
System.out.println("Java's Integer.toBinaryString() version is "+Integer.toBinaryString(Integer.valueOf(args[0])));
if(accumulator.toString().equals(Integer.toBinaryString(Integer.valueOf(args[0])))){System.out.println("The two binary strings match.");}
}
}
ASKER
When the JVM / OS accesses memory - or the registers - how does it interpret the state of the charge on the MSB cell, given that if the charge is on, then the cell is effectively a "1", and if it's off, then there's no charge, and it represents a "0". ?
Is the width of the array the only way that can be overcome? If so, why can't .toBinaryString(int) give the leading zeros . . .
Is the width of the array the only way that can be overcome? If so, why can't .toBinaryString(int) give the leading zeros . . .
If so, why can't .toBinaryString(int) give the leading zeros . . .You described the (very) low level stuff in its essence but the 'leading zeros' thing has a much simpler explanation: it's the difference between visualizing a pattern across the full bit range and rendering as a number. They opted for the latter, and leading zeros have no meaning or function in numbers
ASKER
When I implement Doug's examples (plus my one extra for -123) using .toBinaryString(), this emerges :
Decimal 64 is 1000000
Decimal 123 is 1111011
Decimal -1 is 11111111111111111111111111 111111
Decimal 1 is 1
Decimal -123 is 11111111111111111111111110 000101
The first two are 7-bits long. The next 32 bits, then bitlength 1, and finally bitlength 32 again.
So I ask myself, where's my 32-bits-worth of real estate disappeared to now? Why's it not turned out like Doug's post of :
Decimal 1 is 00000000000000000000000000 000001 ?
After all, toBinaryString() is only sending back a String - why doesn't it get artificially padded at least. It's not as if you can operationally use it for anything?
Decimal 64 is 1000000
Decimal 123 is 1111011
Decimal -1 is 11111111111111111111111111
Decimal 1 is 1
Decimal -123 is 11111111111111111111111110
The first two are 7-bits long. The next 32 bits, then bitlength 1, and finally bitlength 32 again.
So I ask myself, where's my 32-bits-worth of real estate disappeared to now? Why's it not turned out like Doug's post of :
Decimal 1 is 00000000000000000000000000
After all, toBinaryString() is only sending back a String - why doesn't it get artificially padded at least. It's not as if you can operationally use it for anything?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I hesitate to make an additional comment really, as it will not affect the way things happen, but as Doug has said, it all comes down to the number of bits anyone is talking about at the time - which is, almost comically, a stunningly facile explanation for what lies behind the apparent difficulty.
But . . . int, and Integer, are defined in 32 bits - a Dword.
The number of bits required (in an initial 1s or 0s String mask) to represent any particular, negative int/Integer, is * :
The number of bits required to represent any particular positive int is ** :
These two *-starred indexes then identify the righthandmost starting positions for the commencement of the actual payload of the decimal int given. This ends up in a full 32-bit representation of all in-range ints, with all leading 1s (and more importantly, leading 0s for positive numbers) as a String.
(I'm not going to go anywhere near BigInteger, fear not. Nor what might be going on in the 64-bit quadword world if it's even a question that it might need to ' get its head around ' binary maths).
One more thought, sorry, now : OK the memory cells and their charges can only represent a positive - on or off. (You can't 'prove' a negative, so the no-charge cell is muted). But the Runtime knows the length of the allocated cells for the var (int) in question. So what's stopping the runtime using the state of the cell at the base of the offset being read?
But . . . int, and Integer, are defined in 32 bits - a Dword.
The number of bits required (in an initial 1s or 0s String mask) to represent any particular, negative int/Integer, is * :
((int)Math.ceil(Math.log10(your_Negative_Int)/Math.log10(2))+1)//ALL 1s
The number of bits required to represent any particular positive int is ** :
((int)Math.ceil(Math.log10(your_Positive_Int)/Math.log10(2)))//ALL 0s
These two *-starred indexes then identify the righthandmost starting positions for the commencement of the actual payload of the decimal int given. This ends up in a full 32-bit representation of all in-range ints, with all leading 1s (and more importantly, leading 0s for positive numbers) as a String.
(I'm not going to go anywhere near BigInteger, fear not. Nor what might be going on in the 64-bit quadword world if it's even a question that it might need to ' get its head around ' binary maths).
One more thought, sorry, now : OK the memory cells and their charges can only represent a positive - on or off. (You can't 'prove' a negative, so the no-charge cell is muted). But the Runtime knows the length of the allocated cells for the var (int) in question. So what's stopping the runtime using the state of the cell at the base of the offset being read?
So what's stopping the runtime using the state of the cell at the base of the offset being read?Do you mean "Why are there no leading zeros?"
ASKER
Do you mean "Why are there no leading zeros?"
Well, I shalln't say 'yes' to that, because you've already answered it I think, saying that leading zeros are meaningless in a number, which is entirely correct.
But in a String representation of the leading zeros (which is I guess what our whole convo is about), why isn't it possible for the allocated int space in memory (I guess the int is held on the stack, but an Integer is held in RAM I assume) which has a known starting and ending offset, to be interrogated at (endianness correctly) index "leftmost" for a 0 or a 1 - charge or no charge? The runtime must know what's going on at each index, so however long the bitcount is, the start of its offset must be a readable value? Or am I going crazy?
It's always possible to query the bits of the numeric primitive you're using
ASKER
Well, given that Java won't let you deal with anything smaller than a byte - let alone a single bit - it's a big challenge to see how it's possible to query individual bits in a primitive, and if possible could you kindly indicate how you'd go about that?
There's this array of method accessors which don't seem to get anywhere close to returning a result of that sort, or allowing some further queryable token to be returned that can allow it to be done -:
There's this array of method accessors which don't seem to get anywhere close to returning a result of that sort, or allowing some further queryable token to be returned that can allow it to be done -:
int ii = -1;
System.out.println("The binary string for "+ii+" is "+Integer.toBinaryString(ii));
System.out.println("Length of binary for "+ii+" is "+Integer.toBinaryString(ii).length());
System.out.println("Leading 0s in "+ii+" is " +Integer.numberOfLeadingZeros(ii));
System.out.println("Trailing 0s in "+ii+" is " +Integer.numberOfTrailingZeros(ii));
System.out.println("Bitcount for "+ii+" is " +Integer.bitCount(ii));
System.out.println("Radix 2 string rep for "+ii+" is " +Integer.toString(ii,2));
System.out.println("Unsigned Radix 2 string rep for "+ii+" is " +Integer.toUnsignedString(ii,2));
System.out.println("SIZE of "+ii+" is " +((Integer)ii).SIZE);
System.out.println("BYTES of "+ii+" is " +((Integer)ii).BYTES);
Something like
public static String toBinaryString(short n) {
char[] a = new char[16];
Arrays.fill(a, '0');
StringBuilder sb = new StringBuilder(new String(a));
for (int bit = 0; bit < 16; bit++) {
if (((n >> bit) & 1) > 0) {
sb.setCharAt(15 - bit, '1');
}
}
return sb.toString();
}
ASKER
OK, but I paused to try to see why that code produces a leading 0 MSB string when dealing with a negative input , but I can't. (Also, why is it taking a short when the infamous .toBinaryString works on an int)? Thnx.
Sorry - sloppy off-by-one error. Now corrected.
All primitives have toBinaryString, that just happened to be for short
All primitives have toBinaryString, that just happened to be for short
ASKER
All primitives have toBinaryString, that just happened to be for short
I never realised that primitives themselves had any methods. Even Short doesn't have a toBinaryString() method afaics . . .
Sorry - I phrased that badly. I meant that I originally (in my own routines) overloaded the toBinaryString method for all primitives. Yes, in the JDK, some, but not all of, wrapper classes have these methods
ASKER
On a 'personal' level (if there is even any such thing in the context), it's disappointing that whilst the OS and the JVM together can get oversight of the binary condition of any part of memory, that the system can't disclose - on a 'read-only' basis if nothing else - what .toBinaryString() superficially promises. All it succeeds in doing is to fall short of expectations.
Mind you, there are so many deprecated methods already, maybe they also caused some early rocket misadventures.
All that I've got to do now is to get why "static final char[] digits = {" in Doug's earlier comment is applicable.
Mind you, there are so many deprecated methods already, maybe they also caused some early rocket misadventures.
All that I've got to do now is to get why "static final char[] digits = {" in Doug's earlier comment is applicable.
Don't quite follow you there.
As for Doug's thing:
As for Doug's thing:
All possible chars for representing a number as a StringI think the number of "possible chars" is open to interpretation (e.g. character case can be involved) but certainly it allows up to 'standard' base 36 to be used
ASKER
Don't quite follow you there.NTW.. ;)
Try ensuring that bit is present in the argument, e.g. 0xFF00FF00 and see what happens
That's actually a low value. Only negative when a byte type