Why does `%4.` add space to my number? - java

I have this code:
private String padWithZeroRightToPeriod(String serverFormat, float unformattedNumber, int index) {
int nDigits = getNumberOfDigitsAfterPeriod(serverFormat);
String floatingFormat = "%4." + nDigits + "f";
String formattedPrice = String.format(floatingFormat, unformattedNumber);
When called with unformattedNumber being 846, why is the result " 846" (a space and then the three digits)?
What does the %4. mean?

The docs for String.format refer you to this documentation on format strings, which says:
The format specifiers for general, character, and numeric types have the following syntax:
%[argument_index$][flags][width][.precision]conversion
The optional argument_index is a decimal integer indicating the position of the argument in the argument list. The first argument is referenced by "1$", the second by "2$", etc.
The optional flags is a set of characters that modify the output format. The set of valid flags depends on the conversion.
The optional width is a positive decimal integer indicating the minimum number of characters to be written to the output.
The optional precision is a non-negative decimal integer usually used to restrict the number of characters. The specific behavior depends on the conversion.
The required conversion is a character indicating how the argument should be formatted. The set of valid conversions for a given argument depends on the argument's data type.
From your example output, it appears that getNumberOfDigitsAfterPeriod is returing 0, so your format string is %4.0f. So:
It doesn't have an argument index (there's no $ after the 4)
It has a width (4)
It has a precision (0)
And of course it has a conversion (f)
So 846 is output as " 846" because the width is 4. The width in question is the total number of characters output. Here's a different example: Live Copy
public class Example {
public static void main(String args[]) {
System.out.println(String.format("%8.2f", 846.0));
System.out.println(String.format("%8.2f", 42.4));
}
}
Output:
846.00
42.40
Note that each of those is eight characters long.

Related

The width of a double variable

I am trying to write some text to a file using PrintWriter and I do not understand what "7" means in the next example:
double d = 12.11211;
out.format(“%7.3f”, d);
The source from where I am inspiring says that 7 means:
The 7.3 before the f denotes the width (7) and precision (3) to output
d in.
The problem is that I cannot understand what that width really means. I mean, even though my variable would have more than 7 digits, it is not going to format anything.
Think of it as the total length of the string produced by the applied format.
If you take in account that there will be exactly 3 chars after the decimal point and 1 char for the decimal point itself, then it leaves 3 chars for the integer part.
Because your number has only 2 digits in the integer part the final result will be padded at the left with a white space:
double d = 12.11211;
out.format("%7.3f", d);
will create:
" 12.112"
with
out.format("%8.3f", d);
you get
" 12.112"
and so on.
The minimum length of the formatted string is in your case:
6 = 2 chars for the integer part + 1 char for the decimal point + 3 chars for the digits after the decimal point
so even if you set:
out.format("%5.3f", d);
this will not truncate the result, it will be:
"12.112"
For simple text arguments, you can think of the width and precision as a minimum and maximum number of characters to be output. For floating-point numeric types, the precision changes meaning slightly and controls the number of digits displayed after the decimal point.
watch this example:
System.out.printf("String is '%5s'\n", "A");
// String is ' A'
System.out.printf("String is '%.5s'\n", "Happy Birthday!");
// String is 'Happy'
for more information look at this link
Your source of inspiration should be the javadoc. It says:
The width is the minimum number of characters to be written to the
output. If the length of the converted value is less than the width
then the output will be padded by ' ' ('\u0020') until the total
number of characters equals the width. The padding is on the left by
default.[...]
For the floating-point conversions 'a', 'A', 'e', 'E', and 'f' the precision is the number of digits after the radix point.
A simple experiment shows it:
System.out.printf("%7.3f%n", 1.3);
System.out.printf("%7.3f%n", 12.3);
System.out.printf("%7.3f%n", 12.34);
System.out.printf("%7.3f%n", 12.345);
System.out.printf("%7.3f%n", 12.3456);
System.out.printf("%7.3f%n", 12.34567);
System.out.printf("%7.3f%n", 12.34567);
System.out.printf("%7.3f%n", 123.34567);
System.out.printf("%7.3f%n", 1234.34567);
System.out.printf("%7.3f%n", 12345.34567);
prints:
1,300
12,300
12,340
12,345
12,346
12,346
12,346
123,346
1234,346
12345,346
By width, it means the string will always fill the rest of the places if the number of digits/characters of the value is less than the given number.
double d = 12.11211;
String.format(“%7.3f”, d);
> 12.112
^^^^^^^
1234567
According to this:
The field width in a formatting operator is a nonnegative integer that
specifies the number of digits or characters in the output when
formatting input values. For example, in the operator %7.3f, the field
width is 7.
By default, the output text is padded with space
characters when the field width is greater than the number of
characters.
The 7 adds padding () in case the output is smaller than 7 characters. This way the output is always at least 7 characters, with 3 floating decimals.
This documentation gives a very detailed explanation for formatting text in general, most of which is applicable cross-language.

Convert string to byte getting number format exception

public class HelloWorld{
public static void main(String []args){
String str = "100.00";
Short sObj2 = Short.valueOf(str);
System.out.println(sObj2);
}
}
Getting below exception :
Exception in thread "main" java.lang.NumberFormatException: For input string: "100.00"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Short.parseShort(Short.java:118)
at java.lang.Short.valueOf(Short.java:174)
at java.lang.Short.valueOf(Short.java:200)
at HelloWorld.main(HelloWorld.java:5)
How to resolve above issue?
First a Short is not a byte (your question summary indicates you are trying to convert a string to a byte). A Short holds integer values from -32,768 to 32,767 (inclusive). Trying to parse a floating point value into an integer datatype causes this exception.
If you simply want code that will run without an exception, either of the following should work:
public class HelloWorld{
public static void main(String []args){
String str = "100";
Short sObj2 = Short.valueOf(str);
System.out.println(sObj2);
}
}
This first example makes it run by changing the string to an integer value.
or
public class HelloWorld{
public static void main(String []args){
String str = "100.00";
Double sObj2 = Double.valueOf(str);
System.out.println(sObj2);
}
}
This second one works by parsing a string representing a floating point value into a variable type that supports floating points.
Try this
String str = "100";
Short sObj2 = Short.valueOf(str);
or if you want to deal with decimal values,
String str = "100.00";
Float fObj2 = Float.valueOf(str);
To begin with, as your post title suggests, you want to convert from a String data type to a byte data type. This doesn't necessarily include just displaying the a value which doesn't generate a NumberFormatException error. I'm assuming you actually want to work with those particular data types.
To throw a small twist into things, you want to convert all this from a string representation of a numerical value which can be from either a float or double data type ("100.00"). It's this decimal point within the numerical string that throws a glitch into things when doing any conversion and therefore needs to be handled before doing any such thing.
Some things to consider:
As a String, you can represent any number you like in any format you like. It can be as big as you want and it can be as small as you want. I can even be a number that is imaginary or doesn't exist, but the bottom line is....it will always be a String and you can do such things with String data types. Converting a String numerical value to an actual numerical data type such as byte, short, integer, long, double, float, etc is a different ball game altogether. Some String numerical values are easy to convert and yet some require more specific attention to detail.
A byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive).
A short data type is a 16-bit signed two's complement integer. It has a minimum value of -32,768 and a maximum value of 32,767 (inclusive).
The int (integer) data type is a 32-bit signed two's complement integer, which has a minimum value of -2147483648 and a maximum value of 2147483647.
The long data type is a 64-bit two's complement integer. The signed long has a minimum value of -9223372036854775808 and a maximum value of 9223372036854775807.
At the end of it all these four data types all maintain integer values with each data type also maintaining a minimum and maximum of values. You need to also consider this to some extent when doing data type conversions. If you are going to create a conversion method to convert from one data type to another you need to ensure that you do not exceed that minimum and maximum allowable value for the data type you want to convert to. Not a big deal if you want to convert a byte data type to a short data type or a short to an integer since we know that the lesser will always play in the larger but this is not necessarily so when a larger is to play in a lesser (short to byte).
Your conversion method needs to check the value to convert so as to ensure it will actually fit into the desired data type. Java has constants to assist you with this so that you don't have to remember these minimums and maximums, for example: Integer.MIN_VALUE and Integer.MAX_VALUE or Byte.MIN_VALUE and Byte.MAX_VALUE.
When dealing with numerical strings you may also want to ensure that the string you're dealing with is actually a string representation of a numerical value and not a alphanumeric value such as that of a Hexidecimal string or just a plain out entry error whereas a character other than a digit has crept into the string somehow. In my opinion, the string: "100.00" is a string representation of both a alphanumeric value (because of the period) and a numeric value since it is a string representation of a double data type. What it will truly be depends upon how you handle the period (decimal point) in the string within your conversion method.
Let's take another look at that string value ("100.00"). Another thing you may want to consider is, what if our string value was: "100.74"? How do you want to handle this particular value? Do you want to Round Down to 100 or *Round Up to 101 before you convert it to a data type that requires a integer value?
Let's convert the String representation of the value "100.00" to a short data type. Now keep in mind that the methods I provide below by default will always convert a string representation of a double data type (if supplied) downwards, for example 100.45 or 100.99 will be 100. If you want to properly round up or down for this type of value then supply a boolean true in the optional roundUpDown argument:
private short StringToShort(final String input, final boolean... roundUpDown) {
// Make sure there no dead whitespaces...
String inputValue = input.replaceAll(" ", "");
int i = 0; // default return value is 0
// If inputValue contains nothing ("") then return 0
if(inputValue.equals("")) { return 0; }
// Is inputValue an actual numerical value?
// Throws an exception if not.
// Handles negative and decimal point...
if (!inputValue.matches("-?\\d+(\\.\\d+)?")) {
throw new IllegalArgumentException("\nStringToShort() Method Error!\n"
+ "The value supplied is not numeric (" + inputValue + ").\n");
}
// Was the optional roundUpDown argument supplied?
boolean round = false; // default is false
if (roundUpDown.length > 0) { round = roundUpDown[0]; }
// Convert the String to a Integer value
if (inputValue.contains(".")) {
// Must be a double type representation supplied
Double value = Double.parseDouble(inputValue);
if (round) { i = (int) Math.round(value); }
else { i = (int) value.intValue(); }
}
else {
// Must be a Integer type representation supplied
i = Integer.parseInt(inputValue);
}
// Is the Integer value now too small or too
// large to be a Short data type?
if (i > Short.MAX_VALUE || i < Short.MIN_VALUE) {
throw new IllegalArgumentException("\nStringToShort() Method Error!\n"
+ "The value supplied is too small or too large (" + inputValue + ").\n"
+ "Only values from " + Short.MIN_VALUE + " to " + Short.MAX_VALUE
+ " are allowed!\n");
}
// Finally, cast and return a short data type...
return (short) i;
}
If you read all the comments within the code you can see that we've covered all the issues discussed above. Now, according to your post title, you wanted to convert to byte. Well, it's pretty much the very same method but with perhaps five or so small changes done, see if you can spot them:
private byte StringToByte(final String input, final boolean... roundUpDown) {
// Make sure there no dead whitespaces...
String inputValue = input.replaceAll(" ", "");
int i = 0; // default return value is 0
// If inputValue contains nothing ("") then return 0
if(inputValue.equals("")) { return 0; }
// Is inputValue an actual numerical value?
// Throws an exception if not.
// Handles negative and decimal point...
if (!inputValue.matches("-?\\d+(\\.\\d+)?")) {
throw new IllegalArgumentException("\nStringToByte() Method Error!\n"
+ "The value supplied is not numeric (" + inputValue + ").\n");
}
// Was the optional roundUpDown argument supplied?
boolean round = false; // default is false
if (roundUpDown.length > 0) { round = roundUpDown[0]; }
// Convert the String to a Integer value
if (inputValue.contains(".")) {
// Must be a double type representation supplied
Double value = Double.parseDouble(inputValue);
if (round) { i = (int) Math.round(value); }
else { i = (int) value.intValue(); }
}
else {
// Must be a Integer type representation supplied
i = Integer.parseInt(inputValue);
}
// Is the Integer value now too small or too
// large to be a Byte data type?
if (i > Byte.MAX_VALUE || i < Byte.MIN_VALUE) {
throw new IllegalArgumentException("\nStringToByte() Method Error!\n"
+ "The value supplied is too small or too large (" + inputValue + ").\n"
+ "Only values from " + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE
+ " are allowed!\n");
}
// Finally, cast and return a byte data type...
return (byte) i;
}

Neat way to find the number of significant digits in a BigDecimal?

I do not want to limit the number of significant digits in a BigDecimal. I only want to find the number of significant digits that number has.
Is there a way to do this without converting the number to string and count the number characters?
I believe you want a combination of stripTrailingZeros, precision and scale, as demonstrated here:
import java.math.*;
public class Test {
public static void main(String[] args) {
test("5000"); // 4
test("5000.00"); // 4
test("5000.12"); // 6
test("35000"); // 5
test("35000.00"); // 5
test("35000.12"); // 7
test("35000.120"); // 7
test("0.0034"); // 2
test("1.0034"); // 5
test("1.00340"); // 5
}
private static void test(String input) {
System.out.println(input + " => " +
significantDigits(new BigDecimal(input)));
}
private static int significantDigits(BigDecimal input) {
input = input.stripTrailingZeros();
return input.scale() < 0
? input.precision() - input.scale()
: input.precision();
}
}
The call to stripTrailingZeros is required as otherwise it's entirely possible for a BigDecimal to be stored in a "non-normalized" form. For example, new BigDecimal(5000) has a precision of 4, not 1.
The call to scale() is used to handle cases where the normalized form has trailing zeroes before the decimal point, but nothing after the decimal point. In this case, the scale will always be negative, and indicates the number of trailing zeroes.
EDIT: Cases with trailing zeroes but no decimal point are inherently ambiguous - there's no definite number of significant digits to "5000" for example. The above code treats all trailing zeroes before the decimal point as significant.
The following modification of Jon's answer returns the results that seem correct to me:
private static int significantDigits(BigDecimal input) {
return input.scale() <= 0
? input.precision() + input.stripTrailingZeros().scale()
: input.precision();
}
(Note that input.stripTrailingZeros().scale() appears to always be negative in these tests.)
Also, as I noted above, BigDecimal isn't capable of distinguishing between, say, a "5000" with one significant digit and a "5000" with two, for example. Furthermore, according to the definitions, "5000." (with a trailing decimal point) should have exactly four significant digits, but BigDecimal isn't capable of handling that. (See http://en.wikipedia.org/wiki/Significant_figures for the definitions I'm using.)
Jon's answer is correct in most cases except exponential number:
private static int significantDigits(BigDecimal input) {
return input.scale() <= 0
? input.precision() + input.stripTrailingZeros().scale()
: input.precision();
}
let's say the input as 1.230000E17, the function returns 18 however the correct significant digits should be 7.

What is the method in the API for converting between bases?

What is the method that you can use to convert between bases in Java? It is something like IntegerToBase (int, base), but I cannot remember.
Literally speaking, integer values are not converted from one base to another. Thanks to von Neumann, one of the pioneers of computing, who thought the idea of trying to use base 10 arithmetic on binary circuitry made little sense, integers are stored in binary format and we are not trying to change that :-) What we are talking about is converting them to strings representing them in some base (other that base 10 which is the default) and converting strings to integers in bases other than (the default) base 10. The necessary tools are static methods of the Integer class.
Java provides the Integer.toString(int i, int radix) conversion function which takes an integer and a radix (the base) and returns that integer's string representation in that base.
String hexRepr = Integer.toString(255, 16) // returns "FF"
To go the other way around, i.e. from a string representing a number in a different base there is Integer.parseInt(String s, int radix)
int myNum = Integer.parseInt("FF", 16) // returns 255
To convert a number represented as a base radix1 string to a base radix2 string representation the two methods just mentioned have to be combined as the following examples shows:
int radix1 = 16; // The input will be parsed assuming base 16 representation
int radix2 = 4; // The result will be output using a base 4 representation
String input = "FF"; // which in base 16 represents the number 255
String converted = Integer.toString(Integer.parseInt(radix1Representation, radix1),radix2); /// returns "3333" which in base 4 is the number 255
More details can be found in the API documentation. I have included some of it here, to ensure readers also see the things they need to be careful with when using these methods.
public static String toString(int i, int radix)
This method returns a string representation of the first argument in the radix specified by the second argument.
If the radix is smaller than Character.MIN_RADIX or larger than Character.MAX_RADIX, then the radix 10 is used instead.
If the first argument is negative, the first element of the result is the ASCII minus character '-' ('\u002D'). If the first argument is not negative, no sign character appears in the result.
The remaining characters of the result represent the magnitude of the first argument. If the magnitude is zero, it is represented by a single zero character '0' ('\u0030'); otherwise, the first character of the representation of the magnitude will not be the zero character. The following ASCII characters are used as digits:
0123456789abcdefghijklmnopqrstuvwxyz
These are '\u0030' through '\u0039' and '\u0061' through '\u007A'. If radix is N, then the first N of these characters are used as radix-N digits in the order shown. Thus, the digits for hexadecimal (radix 16) are 0123456789abcdef. If uppercase letters are desired, the String.toUpperCase() method may be called on the result:
Integer.toString(n, 16).toUpperCase()
Source: http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#toString%28int,%20int%29
public static int parseInt(String s, int radix) throws NumberFormatException
This method parses the string argument as a signed integer in the radix specified by the second argument. The characters in the string must all be digits of the specified radix (as determined by whether Character.digit(char, int) returns a nonnegative value), except that the first character may be an ASCII minus sign '-' ('\u002D') to indicate a negative value or an ASCII plus sign '+' ('\u002B') to indicate a positive value. The resulting integer value is returned.
An exception of type NumberFormatException is thrown if any of the following situations occurs:
The first argument is null or is a string of length zero.
The radix is either smaller than Character.MIN_RADIX or larger than Character.MAX_RADIX.
Any character of the string is not a digit of the specified radix, except that the first character may be a minus sign '-' ('\u002D') or plus sign '+' ('\u002B') provided that the string is longer than length 1.
The value represented by the string is not a value of type int.
Examples:
parseInt("0", 10) // returns 0
parseInt("473", 10) // returns 473
parseInt("+42", 10) // returns 42
parseInt("-0", 10) // returns 0
parseInt("-FF", 16) // returns -255
parseInt("1100110", 2) // returns 102
parseInt("2147483647", 10) // returns 2147483647
parseInt("-2147483648", 10) // returns -2147483648
parseInt("2147483648", 10) // throws NumberFormatException
parseInt("99", 8) // throws NumberFormatException
parseInt("Kona", 10) // throws NumberFormatException
parseInt("Kona", 27) // returns 411787
Source: http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#parseInt%28java.lang.String,%20int%29
The Integer class offers two utility methods which offer this functionality, although strings are the medium of conversion:
Integer.parseInt(String s, int radix) to parse from a given base
Integer.toString(int i, int radix) to convert to a given base
Note that Integer internally stores values in decimal form (base 10).
For example, to convert 01000 (octal) to 512 (decimal) and back, you can do the following:
String octal = "01000";
int i = Integer.parseInt(octal, 8);
String decimal = Integer.toString(i, 10);
System.out.println(decimal); // prints 512
You can use Integer.parseInt("101", 2) for example, it will give you 5 (correspond decimal number).
Returns an Integer object holding the value extracted from the
specified String when parsed with the radix given by the second
argument. The first argument is interpreted as representing a signed
integer in the radix specified by the second argument, exactly as if
the arguments were given to the parseInt(java.lang.String, int)
method. The result is an Integer object that represents the integer
value specified by the string. In other words, this method returns an
Integer object equal to the value of: (source)
new Integer(Integer.parseInt(s, radix))
From the same source, you also have:
public static String toString(int i,int radix)
Returns a string representation of the first argument in the radix specified by the second argument.
So if you want to convert from binary to decimal:
Integer.parseInt(binary_number_in_string, 2);
if you want from decimal to binary:
System.out.println(Integer.toString(2,2));
To convert from another base to decimal and vise versa you just have to change the radix parameter.
Note that the class Integer have already some default conversation methods, such as:
public static String toBinaryString(int i)
Returns a string representation of the integer argument as an unsigned integer in base 2
(source).
public static String toHexString(int i)
Returns a string representation of the integer argument as an unsigned integer in base 16 (source).
public static String toOctalString(int i)
Returns a string representation of the integer argument as an unsigned
integer in base 8 (source).
As you can see from the return type of the above methods, it is not the integer that are being convert between base. The methods are returning the String representation in a give base of the integer pass as a argument.

Unexpected NumberFormatException while parsing a hex string to an int value

I want to parse an String containing 8 hex-digits (4bytes) but i got an NumberFormatException. What is wrong here?
assertThat(Integer.parseInt("FFFF4C6A",16),is(0xFFFF4C6A));
Your number represents a number greater than that assignable to an int. Try:
Long.parseLong("FFFF4C6A", 16);
which gives 4294921322.
From the doc:
An exception of type NumberFormatException is thrown if any of the following situations occurs:
The first argument is null or is a string of length zero.
The radix is either smaller than Character.MIN_RADIX or larger than Character.MAX_RADIX.
Any character of the string is not a digit of the specified radix, …
The value represented by the string is not a value of type int.
and it's the 4th case that you're hitting.
You've exceeded the range of an integer.
Integer.MAX_VALUE = 2147483647
0xFFFF4C6A = 4294921322
Parsing it as a Long works:
Long.parseLong("FFFF4C6A",16)
That is because the Integer.parseInt("FFFF4C6A",16) provided exceeds Integer.MAX_VALUE which is defined as public static final int MAX_VALUE = 0x7fffffff;
Now, as per the Javadoc for parseInt(...), you would hit a NumberFormatException in either of the following cases:
An exception of type NumberFormatException is thrown if any of the following situations occurs:
The first argument is null or is a string of length zero.
The radix is either smaller than Character.MIN_RADIX or larger than Character.MAX_RADIX.
Any character of the string is not a digit of the specified radix, except that the first character may be a minus sign '-' ('\u002D') or
plus sign '+' ('\u002B') provided that the string is longer than
length 1.
The value represented by the string is not a value of type int.
In your case, since the String value supplied exceeds Integer.MAX_VALUE, you're satisfying the 4th clause for NumberFormatException
Possible Solution: In order to parse this, use Long.parseLong(...) where the MAX_VALUE is defined as `public static final long MAX_VALUE = 0x7fffffffffffffffL
If you just want to represent that hex string as an integer (since it is 32 bits), you need to use BigInteger:
new BigInteger("FFFF4C6A", 16).intValue()
I don't know the assertThat() method, but your hexadecimal number "FFFF4C6A" is to big for an integer.
For example, if you write :
int number = Integer.parseInt("FFFF4C6A",16)
you'll get the same error.
A correct way to write the code would be :
double number = Integer.parseInt("FFFF4C6A",16)

Categories

Resources