java equivalent to printf("%*.*f") - java

In C, the printf() statement allows the precision lengths to be supplied in the parameter list.
printf("%*.*f", 7, 3, floatValue);
where the asterisks are replaced with first and second values, respectively.
I am looking for an equivalent in Android/Java; String.format() throws an exception.
EDIT: Thanks, #Tenner; it indeed works.

I use
int places = 7;
int decimals = 3;
String.format("%" + places + "." + decimals + "f", floatValue);
A little ugly (and string concatenation makes it not perform well), but it works.

System.out.print(String.format("%.1f",floatValue));
This prints the floatValue with 1 decimal of precision

You could format the format :
String f = String.format("%%%d.%df", 7, 3);
System.out.println(f);
System.out.format(f, 111.1111);
This will output :
%7.3f
111,111
You could also use a little helper like this :
public static String deepFormatter(String format, Object[]... args) {
String result = format;
for (int i = 0; i != args.length; ++i) {
result = String.format(result, args[i]);
}
return result;
}
The following call would then be equivalent as the code above and return 111,111.
deepFormatter("%%%d.%df", new Object[] {7, 3}, new Object[] {111.1111});
It's not as pretty as printf, and the input format can become cluttered, but you can do much more with it.

Its like this...
%AFWPdatatype
A - Number of Arguments
F - Flags
W - Width
P - Precision
String.format("%.1f",float_Val);

Related

Converting a double to a string fraction(shoe sizes)

So for my project I have to write a method to convert double values to a string. I understand how to do this multiple ways multiple options of formatting. What I'm confused about is how would I turn half sizes(shoes) into a fraction version while still converting it to a string. So
10.5
returns
10 - 1/2
Any tips or helpful pointers are appreciated. Sorry if this is a dumb question I am still learning. :)
What you want can be done with the modulus operator (%) which in Java can be used with floating point values. If you do shoeSize % 1 you will get 0.5 with half sizes and 0.0 with others, so you only have to check that value to add the "1/2" to the string representation or not. Here is a simple example
public class ShoeSize {
double size;
public ShoeSize(double size) { this.size = size; }
public String toString() {
return "" + (int)size + (size % 1 == 0.5? " 1/2" : "");
}
public static void main(String args[]) {
ShoeSize ss1 = new ShoeSize(10.5);
ShoeSize ss2 = new ShoeSize(11);
ShoeSize ss3 = new ShoeSize(11.5);
System.out.println(ss1);
System.out.println(ss2);
System.out.println(ss3);
}
}
The result of the previous code is:
10 1/2
11
11 1/2
However, you really shouldn't go with that approach. That is because depending on the way you manage the shoe size values it can lead to unpredictable results, just because arithmetic in floating point values is not precise as it is with integer values. Some simple operations like the following can introduce enough error so the result is not what you expect:
...
public static void main(String args[]) {
ShoeSize ss = new ShoeSize(10.0);
ss.size += 0.1 + 0.2 + 0.3; // Sum it half
System.out.println(ss);
}
This code now prints 10 instead of 10 1/2.
What should you do instead? Well, there are several ways. You could for example store the shoe size inside ints representing, with each unit representing a half. This internal representation will be much error-prone if you have operations like addSize or subtracts. The only problem will be reading the size of the user; the best way is probably having a list of predefined sizes for the user to choose. Here is an example:
public class ShoeSize {
int halves;
public ShoeSize(double size) { this.halves = (int)(size * 2); }
public String toString() {
return "" + (halves / 2) + (halves % 2 == 1? " 1/2": "");
}
public static void main(String args[]) {
ShoeSize ss = new ShoeSize(10.5);
System.out.println(ss);
}
}
Still better, since the shoe sizes use to be very restricted between certain values, you could represent their values in a single enum. Every enum can be constructed from the human-readable string of the size (ex. "10 1/2") and there would never be problems with invalid shoe sizes. The only problem with this approach is the need to define a custom method to obtain the next and previous shoe sizes, but here is a question that can help you with that:
[What's the best way to implement `next` and `previous` on an enum type?
Try this
public String getShoeSize(double size) {
int s = (int)size;
String shoeSize = Integer.toString(s);
//check if it is a half value
if(size > s) {
shoeSize += " - 1/2";
}
return shoeSize;
}
At first convert value of double to string and split it:
double d=10.5;
String s = String.valueOf(d);
String[] newstr =s.split(".");
then if fraction is limited use switch case for .5 , .25 , .75
but it is not limited ,simplifying fractions is easy if you can folow the steps:
pay attention to this point that maybe your number is not point sign for example 10 that in switch case must be considered
1.find gcd of both num and den, so you have gcd=GCDFind(gcd, num);
2.now, if gcd==1, then the fraction cannot be simplified (it is already in simplified form).
3.if gcd > 1, then newNum = num/gcd; and newDen = den/gcd;
example for limited :
double s = 10.25;
String aString = Double.toString(s);
String[] fraction = aString.split("\\.");
int denominator = (int)Math.pow(10, fraction[1].length());
int numerator = Integer.parseInt(fraction[0] + "" + fraction[1]);
int t=numerator%denominator;
switch(t){
case 0: System.out.println(numerator/denominator);break; //example : 10
case 5: System.out.println(numerator/denominator + " - " +"1/2");break; //example : 10.5
case 25: System.out.println(numerator/denominator + " - " +"1/4");break; //example : 10.25
case 75: System.out.println(numerator/denominator + " - " +"3/4");break; //example : 10.75
default:System.out.println("Not in 1/2, 1/4 or 3/4");
}

Abbreviating numbers in Android, locale sensitive

In my Android project, I am hoping to find a way to abbreviate numbers that is sensitive to various locales. If the number is less than 1000, it is to remain as is; otherwise, I would like the number divided by the largest possible power of 1000 and rounded to two decimal places. So far, I have the below code, which correctly produces the desired results as stated under Output.
public void formatNumbers() {
//Output:
//842 => 842
//24,567 => 24.57k
//356,915 => 356.92k
//7,841,234 => 7.84M
//1,982,452,873 => 1.98B
int[] i = new int[] {842, 24567, 356915, 7841234, 1982452873};
String[] abbr = new String[] {"", "k", "M", "B"};
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.HALF_UP);
for (long i1 : i) {
int thousands = thousands(i1);
String result;
if(thousands == 0) {
result = String.valueOf(i1);
} else {
double d = (double) i1 / Math.pow(1000.0, thousands);
result = df.format(d)+abbr[thousands];
}
System.out.println(i1 + " => " + result);
}
}
public int thousands(double num) {
//returns the number of times the number can be divided by 1000
int n=0;
double comp=1000.0;
while(num>comp) {
n++;
comp*=1000.0;
}
return n;
}
My concern is that I want a way to ensure that the output is sensitive to locale. If I understand correctly, DecimalFormat should take care of conventions such as commas instead of decimals where applicable; this leaves my concern with the suffix. While my output would be generally be understood in the United States for casual purposes (despite the fact that "M" is used to mean "thousands" in some industries, such as finance) and, from my understanding, many areas in Europe which have languages based on Latin, there are many locales that this would not be understood well. Perhaps there is a built-in function that handles this that I have not been able to find. Thank you in advance for your attention to and input on this task.

Remove leading zero and delimiter char for BigDecimal

Our application can get following numbers:
0.1
0.02
0.003
etc.
These values treated by our code as BigDecimal,as far we operate with money.
There is form on web UI, where user should view these floating parts of prices, transformed to following ones:
1
02
003
The question is,how to trim leading zero and delimiter character in input prices. Perhaps BigDecimal class has standard method something like trimLeadingZeroes(),but can't find any.
UPDATE:
trim just leading zero and delimiter symbol
For instance:
1 is 0.1
27 is 0.27
Something like this?
public String getDecimalFractions(BigDecimal value) {
String strValue = value.toPlainString();
int index = strValue.indexOf(".");
if(index != -1) {
return strValue.substring(index+1, strValue.length());
}
return "0";
}
Have you tried calling BigDecimal.unscaledValue? The downside is that 0.13 would then be 13 whereas you possibly want 1.3... it's slightly hard to tell. If you could give more examples, that would really help.
(That approach would also fail if the value were 1000 to start with - you'd end up with 1...)
Could it be something as simple as doing this:
public static BigDecimal fix(String str){
return new BigDecimal("0." + str);
}
so if you make
public static void main(String[] args) {
System.out.println(fix("1"));
System.out.println(fix("02"));
System.out.println(fix("003"));
}
It will print
0.1
0.02
0.003
when ever you have to deal with splitting something its a good bet Strings can be used for it.
You first just convert the bigdecimal into a string
String s=bd.toPlainString();
Then you simply split it as so
String s2=s.split("\\.")[1];
now String s2 contains the numbers after the delimiter
Conversion from BigDecimal to String:
import java.math.BigDecimal;
public class XXX {
public static void main(String[] args){
doIt("123");
doIt("123.1");
doIt("123.01");
doIt("123.0123");
doIt("123.00123");
}
static void doIt(String input){
BigDecimal bdIn = new BigDecimal(input);
System.out.println(bdIn+" -> "+convert(bdIn));
}
static String convert(BigDecimal bdIn) {
BigDecimal bdOut = bdIn.subtract(bdIn.setScale(0, BigDecimal.ROUND_DOWN));
return bdOut.signum() == 0 ? "0" : bdOut.toPlainString().substring(2);
}
}
Results are:
123 -> 0
123.1 -> 1
123.01 -> 01
123.0123 -> 0123
123.00123 -> 00123
The code works directly with any number and takes into account only the fractional part.
It also handles "0.0" gracefully.
Is this the conversion you wanted?
Here is another simple way of doing this - assuming your input is 1.023456
BigDecimal bd = new BigDecimal("1.023456");
BigInteger bi = bd.toBigInteger();
BigDecimal bd2 = bd.subtract(new BigDecimal(bi));
String afterDecimalPoint = bd2.scale() > 0 ?
bd2.toString().substring(2) : "";
This will give the exact result as you were looking for in bd3, i.e. it'll be 023456 for the above example.
It'll work ok for whole numbers too, due to the condition in last line, i.e. 1 will return ""
You could use the string representation of value (a BigDecimal) and StringUtils.substringAfter to do this:
StringUtils.substringAfter(value.toPlainString(), ".")
How about writing an extension method to extend this type. Simple method might multiply number until > 1
public int trimLeadingZeroes(bigint num) {
while (num < 1)
{
num = num * 10;
}
return num;
}
import java.math.BigDecimal;
import java.math.RoundingMode;
public class RemoveZeroes {
static final int SCALE = 10; // decimal range 0.1 ... 0.0000000001
static final String PADDING = "0000000000"; // SCALE number of zeroes
public static void main(String [] arg) {
BigDecimal [] testArray = {
new BigDecimal(0.27),
new BigDecimal(0.1),
new BigDecimal(0.02),
new BigDecimal(0.003),
new BigDecimal(0.0000000001),
};
for (int i = 0; i < testArray.length; i++) {
// normalize to the same scale
BigDecimal b = testArray[i].setScale(SCALE, RoundingMode.FLOOR);
// pad on the left with SCALE number of zeroes
String step1 = PADDING + b.unscaledValue().toString();
// remove extra zeroes from the left
String step2 = step1.substring(step1.length() - SCALE);
// remove extra zeroes from the right
String step3 = step2.replaceAll("0+$", "");
// print result
System.out.println(step3);
}
}
}

Any neat way to limit significant figures with BigDecimal

I want to round a Java BigDecimal to a certain number of significant digits (NOT decimal places), e.g. to 4 digits:
12.3456 => 12.35
123.456 => 123.5
123456 => 123500
etc. The basic problem is how to find the order of magnitude of the BigDecimal, so I can then decide how many place to use after the decimal point.
All I can think of is some horrible loop, dividing by 10 until the result is <1, I am hoping there is a better way.
BTW, the number might be very big (or very small) so I can't convert it to double to use Log on it.
Why not just use round(MathContext)?
BigDecimal value = BigDecimal.valueOf(123456);
BigDecimal wantedValue = value.round(new MathContext(4, RoundingMode.HALF_UP));
The easierst solution is:
int newScale = 4-bd.precision()+bd.scale();
BigDecimal bd2 = bd1.setScale(newScale, RoundingMode.HALF_UP);
No String conversion is necessary, it is based purely on BigDecimal arithmetic and therefore as efficient as possible, you can choose the RoundingMode and it is small. If the output should be a String, simply append .toPlainString().
You can use the following lines:
int digitsRemain = 4;
BigDecimal bd = new BigDecimal("12.3456");
int power = bd.precision() - digitsRemain;
BigDecimal unit = bd.ulp().scaleByPowerOfTen(power);
BigDecimal result = bd.divideToIntegralValue(unit).multiply(unit);
Note: this solution always rounds down to the last digit.
Someone will probably come up with a better solution, but the first thing that comes to mind is chuck it in to a StringBuilder, check whether it contains a '.' and return an appropriate length substring. E.g.:
int n = 5;
StringBuilder sb = new StringBuilder();
sb.append("" + number);
if (sb.indexOf(".") > 0)
{
n++;
}
BigDecimal result = new BigDecimal(sb.substring(0, n));
To me this seems as simple as:
Given N = 5, D = 123.456789
get the string representation of the number, "123.456789"
retrieve the first N-1 digits of the number, "123.4"
evaluate D[N] and D[N+1], in this case "5" and "6"
6 meets the criteria for rounding up (6 > 4), therefore carry 1 and make D[N] = 5+1 = 6
D post rounding is now 123.46
Order can be calculated using Math.floor(Math.log(D)).
hope this helps.
Since BigDecimal is basically a string, perhaps this:
import java.math.BigDecimal;
public class Silly {
public static void main( String[] args ) {
BigDecimal value = new BigDecimal("1.23238756843723E+5");
String valueString = value.toPlainString();
int decimalIndex = valueString.indexOf( '.' );
System.out.println( value + " has " +
(decimalIndex < 0 ? valueString.length() : decimalIndex) +
" digits to the left of the decimal" );
}
}
Which produces this:
123238.756843723 has 6 digits to the left of the decimal
A.H.'s answer is technically correct, but here is a more general (and easier to understand) solution:
import static org.bitbucket.cowwoc.requirements.core.Requirements.assertThat;
/**
* #param value a BigDecimal
* #param desiredPrecision the desired precision of {#code value}
* #param roundingMode the rounding mode to use
* #return a BigDecimal with the desired precision
* #throws NullPointerException if any of the arguments are null
*/
public BigDecimal setPrecision(BigDecimal value, int desiredPrecision, RoundingMode roundingMode)
{
assertThat("value", value).isNotNull();
assertThat("roundingMode", roundingMode).isNotNull();
int decreaseScaleBy = value.precision() - desiredPrecision;
return value.setScale(value.scale() - decreaseScaleBy, roundingMode);
}

Which API can I use to format an int to 2 digits?

What API can I use to format an int to be 2 digits long?
For example, in this loop
for (int i = 0; i < 100; i++) {
System.out.println("i is " + i);
}
What can I use to make sure i is printed out like 01, 02, 10, 55 etc (assuming a range of 01-99 )
You could simply do
System.out.printf("i is %02d%n", i);
Have a look at the documentation for Formatter for details. Relevant parts are:
The format specifiers for general, character, and numeric types have the following syntax:
%[argument_index$][flags][width][.precision]conversion
(In this particular case, you have 0 as flag, 2 as width, and d as conversion.)
Conversion
'd' integral The result is formatted as a decimal integer
Flags
'0' The result will be zero-padded
This formatting syntax can be used in a few other places as well, for instance like this:
String str = String.format("i is %02d", i);
String class actually do formatting.
For your case, try:
String.format("%02d",i)
You can use the DecimalFormat object.
DecimalFormat formatter = new DecimalFormat("#00.###");
int test = 1;
System.out.println(formatter.format(test));
Will print "01".

Categories

Resources