I have a requirement were depending on a particular key value of a map , i need to format the output .
For example if its value greater than 1 then needed to display only 2 decimal points after the value
(12.23) or else if its value is less than 1 , i need to show 4 decimal points after it .
I have written the code its working fine , but i am looking for a better way of doing this (basically i didn't liked if else conditions in my code )
This is my program where depending on the last attribute key value i am formatting the output
package com;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class CustValues {
public static void main(String args[]) {
Map valuesMap = new HashMap();
valuesMap.put("mktCap", "12.4d");
valuesMap.put("last", "0.4344");
valuesMap.put("avgvalue", "34.55");
valuesMap.put("bidprice", "44.44");
Iterator<String> iterator = valuesMap.keySet().iterator();
while (iterator.hasNext()) {
String name = iterator.next().toString();
String value = (String) valuesMap.get(name);
if (name.equals("last")) {
String result = "";
double d = Double.parseDouble(value);
if (d > 1) {
result = formatNumber(value, 2);
} else {
result = formatNumber(value, 4);
}
System.out.println(result);
}
}
}
public static String formatNumber(String s, int decPts) {
double d = Double.parseDouble(s);
if (2 == decPts)
return new DecimalFormat("#,###,###,##0.00").format(d);
else if (0 == decPts)
return new DecimalFormat("#,###,###,##0").format(d);
else if (3 == decPts)
return new DecimalFormat("#,###,###,##0.000").format(d);
else if (4 == decPts)
return new DecimalFormat("0.0000").format(d);
return String.valueOf(d);
}
}
You could create a Map<Integer, DecimalFormat> formats (or a List<DecimalFormat>, if you prefer). Then formatNumber() simply calls formats.get(decPts) to get the correct format.
The logic you're implementing in the formatNumber method is the perfect candidate for a switch statement. Try
switch (decPts) {
case 0:
return new DecimalFormat("#,###,###,##0").format(d);
break;
case 2:
return new DecimalFormat("#,###,###,##0.00").format(d);
break;
...
}
For more info see this tutorial.
edit: Although SJuan76 beat me to it, and I like Code-Guru's idea better!
Building on Code-Guru's answer. You can use a map but to retain the same thread safety and default behavior the code becomes:
public class CustValues {
private static final Map<Integer, String> FORMATS;
static {
Map<Integer, String> formats = new HashMap<Integer, String>();
formats.put( 0, "#,###,###,##0" );
formats.put( 2, "#,###,###,##0.00" );
formats.put( 3, "#,###,###,##0.000" );
formats.put( 4, "0.0000" );
FORMATS = Collections.unmodifiableMap( formats );
}
public static void main(String args[]) {
// Same as before....
}
public static String formatNumber(String s, int decPts) {
double d = Double.parseDouble(s);
String format = FORMATS.get(decPts);
if( format != null ) {
return new DecimalFormat(format).format(d);
}
return String.valueOf(d);
}
}
You need to create a new DecimalFormat for each request instead of reusing it since it is not thread safe. This also handles the cases where decPts is not 0, 2, 3, or 4.
I have method as below:
public static String formatNumber(String s, int decPts) {
double d = Double.parseDouble(s);
if (decPts >= 0 && decPts <= 4) {
DecimalFormat df = new DecimalFormat("###,##0");
df.setMaximumFractionDigits(decPts);
df.setMinimumFractionDigits(decPts);
return df.format(d);
}
return String.valueOf(d);
}
You can use the switch sentence
switch (decPts) {
case 0:
return new DecimalFormat("#,###,###,##0").format(d);
case 2:
...
}
It helps tidy the code for this case. Anyway you would not be able to program in any language without using ìf or similar constructs.
Enums have the advantage of avoiding boxing and unboxing an integer that a map.get call would perform, while only creating the formatters you need one time. Note, you can also could get rid of the second double parse:
enum DisplayFormat {
CURRENCY(new DecimalFormat("#,###,###,#00.00")),
SMALL_CURRENCY(new DecimalFormat("0.000"));
private DecimalFormat f;
public DisplayFormat(DecimalFormat f) {
this.f = f;
}
public String format(double d) {
return this.f.format(d);
}
// Usage:
if (name.equals("last")) {
String result = "";
double d = Double.parseDouble(value);
if (d > 1) {
result = DisplayFormat.SMALL_CURRENCY.format(d)
} else {
result = DisplayFormat.CURRENCY.format(d)
}
System.out.println(result);
}
One really inefficient, but more flexible option would be to generate the format string based on decPts:
public static String formatNumber(String s, int decPts) {
double d = Double.parseDouble(s);
final String baseFormat = "#,###,###,##0";
// TODO: Use a StringBuilder
String format = decPts==0 ? baseFormat : baseFormat + ".";
for (int i=0; i < decPts; i++) {
format += "0";
}
return new DecimalFormat(format).format(d);
}
Again, this is a bad idea unless you need to show an arbitrary number of decimal points or can only determine the way to display the number at run-time, which probably isn't the case.
Related
All I have a floating point number in Finnish local. It is like the following:-
String numberString = "1000,30";
if(numberString.contains(",")){
numberString = numberString.replaceAll(",",".").trim();
}
try {
Number number = Double.parseDouble(numberString);
return number;
}catch (NumberFormatException ex){
System.out.printf(ex.getMessage());
}
return null;
But this number has value 1000.30. I would like the number should I have value 1000,30. How can I have Number with the comma instead of the dot?
This is a basic question it must have been asked earlier. But all I find is in String data type. I don't see any Number data type.
When seeing your comment that the API accepts only Number and that it calls Number#toString() on it, then I see only 1 way to enforce the rightful display. By using your own implementation of Number and overwriting the way Object#toString() works:
public class CorrectlyDisplayedDouble extends Number{
private final Double internal;
public CorrectlyDisplayedDouble(Double internal){
this.internal = internal;
}
public int intValue(){
return internal.intValue();
}
public long longValue(){
return internal.longValue();
}
public float floatValue(){
return internal.floatValue();
}
public double doubleValue(){
return internal.doubleValue();
}
public String toString(){
// replaces periods with commas
return internal.toString().replace(".", ",");
}
}
Which can then be easily created using following snippet, which then also can be passed to your third party API:
Number number = new CorrectlyDisplayedDouble(Double.parseDouble(numberString));
Sample Code :
String number = "1000500000.574";
double amount = Double.parseDouble(number);
DecimalFormat formatter = new DecimalFormat("#,###.00");
System.out.println(formatter.format(amount));
This will help you to understand how Locale exactly works:
public double parse(String decimalAsText) {
NumberFormat decimalFormat = NumberFormat.getNumberInstance(Locale.FRANCE);
decimalAsText = decimalAsText.replace(' ', '\u00a0');
ParsePosition pp = new ParsePosition(0);
Number n = decimalFormat.parse(decimalAsText, pp);
return n.doubleValue();
}
public String parse(double textAsDecimal) {
NumberFormat nf = NumberFormat.getNumberInstance(Locale.FRENCH);
BigDecimal bd = BigDecimal.valueOf(textAsDecimal);
nf.setMaximumFractionDigits(bd.scale());
String s = nf.format(textAsDecimal);
return s;
}
You can use DecimalFormat and Locale, for example:
DecimalFormat dfFrance = (DecimalFormat)DecimalFormat.getInstance(Locale.FRANCE);
dfFrance.applyPattern("###.00");
Number n = 0;
try {
n = dfFrance.parse("1000,30");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(n.doubleValue());
I was wondering if you can create a custom base with your own symbols instead of the one Java applies to you with Integer.parseInt (0-9 and A-P.)
I was thinking of something like this:
public class Base {
private String symbols;
public Base(String symbols) {
this.symbols = symbols;
}
// for example: new Base("0123456789"); would represent base 10
public static String convertBases(Base from, Base to, String toConvert) {
// Takes toConvert which is encoded in base "from" and converts it to base "to"
}
}
I am not sure how to implement this. Does anyone have the code for this?
To do this, you need to first parse the input text in the from base, then format the value in the to base, exactly like you'd need to do if using standard base "alphabet".
public static String convertBases(int fromRadix, int toRadix, String text) {
int value = Integer.parseInt(text, fromRadix);
return Integer.toString(value, toRadix);
}
So, first you implement parse and toString, then implementing convertTo is easy:
public class Base {
private final String symbols;
private final BigInteger radix;
private final Map<Character, Integer> symbolIndex;
public Base(String symbols) {
if (symbols.length() <= 1)
throw new IllegalArgumentException("Must provide at least 2 symbols: length=" + symbols.length());
this.symbols = symbols;
this.radix = BigInteger.valueOf(symbols.length());
this.symbolIndex = new HashMap<>(symbols.length() * 4 / 3 + 1);
for (int i = 0; i < symbols.length(); i++) {
Integer prevIndex = this.symbolIndex.putIfAbsent(symbols.charAt(i), i);
if (prevIndex != null)
throw new IllegalArgumentException("Duplicate symbol at index " + prevIndex +
" and " + i + ": " + symbols.charAt(i));
}
}
public BigInteger parse(String text) {
BigInteger value = BigInteger.ZERO;
for (int i = 0; i < text.length(); i++) {
Integer index = this.symbolIndex.get(text.charAt(i));
if (index == null)
throw new IllegalArgumentException("Not a valid number: " + text);
value = value.multiply(this.radix).add(BigInteger.valueOf(index));
}
return value;
}
public String toString(BigInteger value) {
if (value.signum() < 0)
throw new IllegalArgumentException("Negative value not allowed: " + value);
if (value.signum() == 0)
return this.symbols.substring(0, 1);
StringBuilder buf = new StringBuilder();
for (BigInteger v = value; v.signum() != 0; v = v.divide(this.radix))
buf.append(this.symbols.charAt(v.mod(this.radix).intValue()));
return buf.reverse().toString();
}
public String convertTo(Base newBase, String text) {
return newBase.toString(parse(text));
}
}
Test
Base base3 = new Base("012");
Base base6alpha = new Base("ABCDEF");
System.out.println(base3.convertTo(base6alpha, "0")); // 0 -> A
System.out.println(base3.convertTo(base6alpha, "2")); // 2 -> C
System.out.println(base3.convertTo(base6alpha, "10")); // 3 -> D
System.out.println(base3.convertTo(base6alpha, "200")); // 18 -> DA
Output
A
C
D
DA
Test 2
Base obscure = new Base("^JsdloYF9%");
Base base64 = new Base("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
BigInteger value = new BigInteger("123456789012345678901234567890"); // Too large for int and long
String obscureValue = obscure.toString(value);
String base64Value = base64.toString(value);
System.out.println(obscureValue);
System.out.println(base64Value);
System.out.println(base64.convertTo(obscure, base64Value));
System.out.println(obscure.convertTo(base64, obscureValue));
Output
JsdloYF9%^JsdloYF9%^JsdloYF9%^
BjukP9sNz4O5OPwrS
JsdloYF9%^JsdloYF9%^JsdloYF9%^
BjukP9sNz4O5OPwrS
Let's start with a value type. It holds a string representation and a Base object. (i.e., it has a string representation and a something like a decoder). Why? because we don't want to pass around Strings which we need to look at and "guess" what base they are.
public class CustomNumber {
private final String stringRepresentation;
private final Base base;
public CustomNumber(String stringRepresentation, Base base) {
super();
this.stringRepresentation = stringRepresentation;
this.base = base;
}
public long decimalValue() {
return base.toDecimal(stringRepresentation);
}
public CustomNumber toBase(Base newBase) {
long decimalValue = this.decimalValue();
String stringRep = newBase.fromDecimal(decimalValue);
return new CustomNumber(stringRep, newBase);
}
}
Then we need to define an interface which is broad enough to handle any regular or custom-symbol base. We will later build concrete implementations on top.
public interface Base {
public long toDecimal(String stringRepresentation);
public String fromDecimal(long decimalValue);
}
We are all set. Lets do an example implementation to support the standard decimal number format before going to custom string symbols:
public class StandardBaseLong implements Base{
public long toDecimal(String stringRepresentation) {
return Long.parseLong(stringRepresentation);
}
public String fromDecimal(long decimalValue) {
return Long.toString(decimalValue);
}
}
Now finally, coming to the custom string base:
public class CustomBase implements Base{
private String digits;
public CustomBase(String digits) {
this.digits = digits;
}
public long toDecimal(String stringRepresentation) {
//Write logic to interpret that string as your base
return 0L;
}
public String fromDecimal(long decimalValue) {
//Write logic to generate string output in your base format
return null;
}
}
Now you have a framework to work with various custom and standard bases.
Of course, there could be more customisations and improved features (more convenience constructors, hashCode and equals implementations and arithmetic). But, they are beyond the scope of this answer.
I am having some difficulties getting my custom equation evaluator to work. I pass it a string read from a text file (no spaces except between string words) as equation as well as passing it a map of keywords which link to the values they represent. I have tested that and all of my maps are working properly. Below is my attempt to handle the result regardless of it is an int or a string. These will be the only two allowed entry types. Each side of the equation can have one or two elements to it, separated by either a plus or a minus. The only three operators allowed to evaluate the two sides are <,>,=. Sides are restricted to either having only keywords or only integers, so you can't have something like dexterity + 1 = strength + 2.
The error I am currently getting when I try to compile this class is "no suitable method found for parseint" "method Integer.parseInt(String,int) is not applicable". If I am not mistaken since I am compiling this class directly and not the main class it wouldn't even have the map to make that kind of judgement call. Is this a problem? I am compiling in this way because I have been having issues where recompiling the main class did not recompile secondary class files causing problems.
Any example equation: dexterity>3 or background=Ex Legionary
import java.lang.String;
import java.util.HashMap;
import java.util.Map;
public class Equation {
private String[] sides = new String[2];
private String[] rawEquation = new String[3];
private String[] parts = new String[2];
private String type;
private int[] tempInt = new int[2];
private int[] finalSide = new int[2];
private String[] finalStride = new String[2];
public boolean solve(String equation, Map gladMap) {
if (equation.indexOf("<") > -1) {
sides = equation.split("<");
rawEquation[1] = "<";
} else if (equation.indexOf(">") > -1) {
sides = equation.split(">");
rawEquation[1] = ">";
} else if (equation.indexOf("=") > -1) {
sides = equation.split("=");
rawEquation[1] = "=";
}
rawEquation[0] = sides[0];
rawEquation[2] = sides[1];
for (int d = 0; d < 2; d++) {
if (sides[d].indexOf("+") > -1) {
parts = rawEquation[0].split("\\+");
for (int a = 0; a < 2; a++) {
if (isInteger(parts[a])){
tempInt[a] = Integer.parseInt(parts[a]);
} else {
tempInt[a] = Integer.parseInt(gladMap.get(parts[a]));
}
}
finalSide[d] = tempInt[0]+tempInt[1];
type = "Int";
} else if (rawEquation[0].indexOf("-") > -1) {
parts = rawEquation[0].split("\\-");
for (int a = 0; a < 2; a++) {
if (isInteger(parts[a])){
tempInt[a] = Integer.parseInt(parts[a]);
} else {
tempInt[a] = Integer.parseInt(gladMap.get(parts[a]));
}
}
finalSide[d] = tempInt[0]-tempInt[1];
type = "Int";
} else {
if (isInteger(sides[0])){
finalSide[d] = Integer.parseInt(sides[0]);
} else {
if (isInteger(gladMap.get(sides[0]))) {
finalSide[d] = Integer.parseInt(gladMap.get(sides[0]));
type = "Int";
} else {
finalStride[d] = gladMap.get(sides[0]);
type = "Str";
}
}
}
}
if (rawEquation[1].equals("<")) {
if (type.equals("Int")) {
if (finalSide[0] < finalSide[1]) {
return true;
}
}
} else if (rawEquation[1].equals(">")) {
if (type.equals("Int")) {
if (finalSide[0] > finalSide[1]) {
return true;
}
}
} else {
if (type.equals("Int")) {
if (finalSide[0] == finalSide[1]) {
return true;
}
} else if (type.equals("Str")) {
if (finalStride[0].equals(finalStride[1])) {
return true;
}
}
}
return false;
}
public boolean isInteger( String input ) {
try {
Integer.parseInt( input );
return true;
}
catch( Exception NumberFormatException ) {
return false;
}
}
}
I tried to separate the Integer.parseInt() from the gladMap.get(sides[0]) by creating a temporary string variable, but it didn't change anything. Any help would be appreciated!
Here, the map which you are passing is not with the generic types. Hence, get() will always return an object, which is not an appropriate argument for parseInt() method.
Changing the method signature to
public boolean solve(String equation, Map< String ,String > gladMap) {
should solve the errors.
The problem might be following: your map is untyped so calls like gladMap.get(sides[0]) return Object. Integer.parseInt expects String. You can change it to
gladMap.get(sides[0]).toString().
It think it should work. If value is actual String then toString will return itself, it it is Integer it will be converted to string and parsed back.
Any help or advice would be greatly appreciated. I'm trying to create a simple game which generates ten different, random questions. The questions can contain 2, 3 or 4 integers. So something like this: 55 2 − 4 − 101, 102/3/3, 589 − 281, 123 + 5 6 + 2.
The question will be displayed in a textview and then the user can take a guess, entering values into an edittext and then upon clicking a key on a custom keypad I have created it will check the answer, and then display the next question in the sequence of 10.
I know how to create random numbers, just struggling to work out how to create a whole question with random operators (+, -, /, *).
Big thank you to anyone who has the time to construct a reply.
A little of spare time produced a complete example for your case. Create new RandomMathQuestionGenerator.java file and it is cooked for compilation.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
public class RandomMathQuestionGenerator {
private static final int NUMBER_OF_QUESTIONS = 10;
private static final int MIN_QUESTION_ELEMENTS = 2;
private static final int MAX_QUESTION_ELEMENTS = 4;
private static final int MIN_QUESTION_ELEMENT_VALUE = 1;
private static final int MAX_QUESTION_ELEMENT_VALUE = 100;
private final Random randomGenerator = new Random();
public static void main(String[] args) {
RandomMathQuestionGenerator questionGenerator = new RandomMathQuestionGenerator();
List<Question> randomQuestions = questionGenerator.getGeneratedRandomQuestions();
for (Question question : randomQuestions) {
System.out.println(question);
}
}
public List<Question> getGeneratedRandomQuestions() {
List<Question> randomQuestions = new ArrayList<Question>(NUMBER_OF_QUESTIONS);
for (int i = 0; i < NUMBER_OF_QUESTIONS; i++) {
int randomQuestionElementsCapacity = getRandomQuestionElementsCapacity();
Question question = new Question(randomQuestionElementsCapacity);
for (int j = 0; j < randomQuestionElementsCapacity; j++) {
boolean isLastIteration = j + 1 == randomQuestionElementsCapacity;
QuestionElement questionElement = new QuestionElement();
questionElement.setValue(getRandomQuestionElementValue());
questionElement.setOperator(isLastIteration ? null
: Operator.values()[randomGenerator.nextInt(Operator.values().length)]);
question.addElement(questionElement);
}
randomQuestions.add(question);
}
return randomQuestions;
}
private int getRandomQuestionElementsCapacity() {
return getRandomIntegerFromRange(MIN_QUESTION_ELEMENTS, MAX_QUESTION_ELEMENTS);
}
private int getRandomQuestionElementValue() {
return getRandomIntegerFromRange(MIN_QUESTION_ELEMENT_VALUE, MAX_QUESTION_ELEMENT_VALUE);
}
private int getRandomIntegerFromRange(int min, int max) {
return randomGenerator.nextInt(max - min + 1) + min;
}
}
class Question {
private List<QuestionElement> questionElements;
public Question(int sizeOfQuestionElemets) {
questionElements = new ArrayList<QuestionElement>(sizeOfQuestionElemets);
}
public void addElement(QuestionElement questionElement) {
questionElements.add(questionElement);
}
public List<QuestionElement> getElements() {
return questionElements;
}
public int size() {
return questionElements.size();
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (QuestionElement questionElement : questionElements) {
sb.append(questionElement);
}
return sb.toString().trim();
}
}
class QuestionElement {
private int value;
private Operator operator;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Operator getOperator() {
return operator;
}
public void setOperator(Operator operator) {
this.operator = operator;
}
#Override
public String toString() {
return value + (operator == null ? "" : " " + operator.getDisplayValue()) + " ";
}
}
enum Operator {
PLUS("+"), MINUS("-"), MULTIPLIER("*"), DIVIDER("/");
private String displayValue;
private Operator(String displayValue) {
this.displayValue = displayValue;
}
public String getDisplayValue() {
return displayValue;
}
}
Run and preview. Hope this helps.
Thanks to:
Generating random number in
range
Retrieving random
element from array
Create an array char[] ops = { '+', '-', '/', '*' } and create a random int i in range [0,3], and chose ops[i]
You will need to take care that you do not generate a divide by zero question.
You can make it even more generic by creating an interface MathOp and creating 4 classes that implement it: Divide, Sum , ... and create an array: MathOp[] ops instead of the char[]
Using this, it will also give you much easier time to check the result later on...
Put your operators in an array (4 elements), generate a random integer from 0 to 3, and pick the operator that is at this index in the array.
Do that each time you need to have a random operator, i.e. after every number of your question except the last one.
Make an array that has one entry for each of the operators. Then generate a random number between 0 and the length of the array minus 1.
So since each operation is binary you can just worry about figuring out the base case and then building up your expressions from there.
An easy way would just to select a random number an correlate that which operation will be used.
int displayAnswer(int leftSide, int rightSide, int operation {
int answer;
string operation;
switch(operation) {
case 1:
operation = "+";
answer = leftSide + rightSide;
break;
case 2:
operation = "-";
answer = leftSide - rightSide;
break;
case 3:
operation = "*";
answer = leftSide * rightSide;
break;
case 4:
operation = "/";
answer = leftSide / rightSide:
break;
}
textView.setText(leftSide + operation + rightSide);
return answer;
}
How do I find out the length or the number of digits of the fraction part of a decimal number?
I can see a few aproaches, e.g. with Strings like this one:
public static int getNumberOfFractionDigits(Number number) {
Double fractionPart = number.doubleValue() - number.longValue();
return fractionPart.toString().length() - 2;
}
But what is the best way to determine the length?
I could imagine some problems if I use Strings, e.g. because the locale and number format may be different from system to system. Is there a nice way to calculate it? Maybe without iteration?
Thanks in advance.
Try this:
public static int getNumberOfFractionDigits(Number number) {
if( number == null ) return 0; //or throw
if( number.doubleValue() == 0.0d ) return 0;
BigDecimal bd = new BigDecimal(number.toString());
//BigDecimal bd = BigDecimal.valueOf(number.doubleValue()); // if double precision is ok, just note that you should use BigDecimal.valueOf(double) rather than new BigDecimal(double) due to precision bugs in the latter
bd = bd.stripTrailingZeros(); //convert 1.00 to 1 -> scale will now be 0, except for 0.0 where this doesn't work
return bd.scale();
}
Edit:
If the number is actually an iteger (i.e. fraction of 0) this would still return 1. Thus you might check whether there actually is a fractional part first.
Edit2:
stripTrailingZeros() seems to do the trick, except for 0.0d. Updated the code accordingly.
I just wrote a simple method for this, hope it can help someone.
public static int getFractionDigitsCount(double d) {
if (d >= 1) { //we only need the fraction digits
d = d - (long) d;
}
if (d == 0) { //nothing to count
return 0;
}
d *= 10; //shifts 1 digit to left
int count = 1;
while (d - (long) d != 0) { //keeps shifting until there are no more fractions
d *= 10;
count++;
}
return count;
}
You may use java.text.NumberFormat.
nf = java.text.NumberFormat.getInstance ();
// without BigDecimal, you will reach the limit far before 100
nf.setMaximumFractionDigits (100);
String s = nf.format (number.doubleValue ())
You may set the Decimal-Identifier as you like, and use regular expressions to cut off the leading part, and String.length () to evaluate the rest.
Looks like many offered the Big Decimal. It's easy on the eyes at least.
The code shall work for ya.
package t1;
import java.math.*;
public class ScaleZ {
private static final int MAX_PRECISION = 10;
private static final MathContext mc = new MathContext(MAX_PRECISION, RoundingMode.HALF_EVEN);
public static int getScale(double v){
if (v!=v || v == Double.POSITIVE_INFINITY || v == Double.NEGATIVE_INFINITY)
return 0;//throw exception or return any other stuff
BigDecimal d = new BigDecimal(v, mc);
return Math.max(0, d.stripTrailingZeros().scale());
}
public static void main(String[] args) {
test(0.0);
test(1000d);
test(1d/3);
test(Math.PI);
test(1.244e7);
test(1e11);
}
private static void test(double d) {
System.out.printf("%20s digits %d%n", d, getScale(d));
}
}
That was my best implementation:
public class NumberHandler {
private static NumberFormat formatter = NumberFormat.getInstance(Locale.ENGLISH);
static {
formatter.setMaximumFractionDigits(Integer.MAX_VALUE);
formatter.setGroupingUsed(false);
}
public static int getFractionLength(double doubleNumber) {
String numberStr = formatter.format(doubleNumber);
int dotIndex = numberStr.indexOf(".");
if (dotIndex < 0) {
return 0;
} else {
return numberStr.length() - (dotIndex + 1);
}
}
}
Not effective, probably not perfect, but the other options was worse.
public static int getNumberOfFractionDigits(double d) {
String s = Double.toString(d), afterDecimal="";
afterDecimal = s.subString(s.indexOf(".") + 1, s.length() - 1);
return afterDecimal.length();
}