How to get the length of a numbers fraction part? - java

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();
}

Related

Conversion of decimal into binary using recursion

I want to convert the decimal number into a binary number using recursion in java. I tried a lot but unable to do it. Here is my code:
public class DecimalToBinary {
public static void main(String[] args) {
System.out.println(conversion(2));
}
public static int conversion(int n) {
return reconversion(n);
}
public static int reconversion(int n) {
if(n <= 0)
return 0;
else {
return (int) (n/2 + conversion(n/2));
}
}
}
Integer values are already in binary. The fact that they appear as digits 0 thru 9 when you print them is because they are converted to a string of decimal digits. So you need to return a String of binary digits like so.
public static String conversion(int n) {
String b = "";
if (n > 1) {
// continue shifting until n == 1
b = conversion(n >> 1);
}
// now concatenate the return values based on the logical AND
b += (n & 1);
return b;
}

Reverse a number using String builder in java

Problem Statement: Given a 32-bit signed integer, reverse digits of an integer.
Example 1:
Input: 123
Output: 321
Example 2:
Input: -123
Output: -321
My Solution:
class Solution7{
public int reverse(int x) {
if(x>Integer.MAX_VALUE || x<Integer.MIN_VALUE) {
return 0;
}
StringBuilder S_rev = new StringBuilder();
String S_r_v=S_rev.append(Math.abs(x)).reverse().toString();//.toString() String builder to String
double reverse_no=Double.parseDouble(S_r_v);
if (x < 0) {
return -(int)reverse_no;
}
return (int)reverse_no;
}
}
My Solution is ok for most of the test case. But it cannot pass one test case and I got a error
Error: Line 10: java.lang.NumberFormatException: For input string: "8463847412-"
If someone know what type of error it is please discuss.
Thank you in advance.
It seems like you are trying to pass in Integer.MIN_VALUE
When you pass in the minimum integer value, Math.abs seems to return a negative number as stated here
https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#abs-int-
Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative.
You can either check for x<=Integer.MIN_VALUE and return 0 if x is Integer.MIN_VALUE or handle the special case for Integer.MIN_VALUE
if(x== Integer.MIN_VALUE)
return -8463847412;
By converting number to String and reversing the sign symbol ended up on the end of the value. This makes the number invalid.
You don't have to convert to String or double. You can use module operator % to extract digits:
public int reverse(int x) {
long result = 0;
while (x != 0) {
result *= 10;
result += x % 10;
x /= 10;
}
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
throw new IllegalArgumentException(); // overflow
}
return result;
}
If you necessarily want to implement it using StringBuilder, here it is:
public static void main(String[] args) {
ReverseNum reverseNum = new ReverseNum();
System.out.println(reverseNum.reverse(-123));
System.out.println(reverseNum.reverse(123));
System.out.println(reverseNum.reverse(0));
}
public int reverse(int x) {
int res = 1;
String xStr = String.valueOf(x);
StringBuilder builder = null;
if (xStr.startsWith("-")) {
builder = new StringBuilder(xStr.substring(1));
res = -1;
} else {
builder = new StringBuilder(xStr);
}
return res * Integer.valueOf(builder.reverse().toString());
}
Output:
-321
321
0
P.S. If you want to avoid integer overflow, then you can simply use long instead of int, like this:
public long reverse(int x) {
long res = 1;
String xStr = String.valueOf(x);
StringBuilder builder = null;
if (xStr.startsWith("-")) {
builder = new StringBuilder(xStr.substring(1));
res = -1;
} else {
builder = new StringBuilder(xStr);
}
return res * Long.valueOf(builder.reverse().toString());
}
public class ReverseString {
public static void main(String args[]) {
ReverseString rs = new ReverseString();
System.out.println(rs.reverse(-84638));
System.out.println(rs.reverse(5464867));
}
public long reverse(int number) {
boolean isNegative = number < 0;
StringBuilder reverseBuilder = new StringBuilder();
String reversedString = reverseBuilder.append(Math.abs(number)).reverse().toString();
long reversedStringValue = Long.parseLong(reversedString);
if(isNegative) {
return reversedStringValue * -1;
} else {
return reversedStringValue;
}
}
}
This code provides the output you have mentioned in the requirement. And It also supports for integer overflow. Your requirement is to convert int values. It is okay to get the converted value in the higher format since converted value may not be in the range of int. I have changed the reverse method return type to long.
I have identified a few issues in your code.
public int reverse(int x) {
if(x>Integer.MAX_VALUE || x<Integer.MIN_VALUE) {
return 0;
}
Above code segment, not point of checking whether the value is inside the int range because it is already received in the param as a string. It should throw an error before executing your code lines since it is not able to fit the larger value to int variable.
Finally, the int number you have used is not in the int range. (-8463847412)
What about this?
public class ReverseNumber {
public static void main(String[] args) {
System.out.println(reverse(123456));
System.out.println(reverse(0));
System.out.println(reverse(-987654));
}
private static int reverse(int i) {
final int signum;
if(i < 0) {
signum = -1;
} else {
signum = +1;
}
int reversedNumber = 0;
int current = Math.abs(i);
while(0 < current) {
final int cipher = current % 10;
reversedNumber = Math.addExact(Math.multiplyExact(reversedNumber, 10), cipher);
current = current / 10;
}
return signum * reversedNumber;
}
}
Output:
654321
0
-456789
This solution avoids strings and can handle negative numbers.
It throws an Arithmetic exception if an integer overflow happens.

how to use recursion for converting String to int

I want to convert String input into int using recursion. This is the code I came up with but if my input is 123456 it only returns 124. If I enter 1234567, it gives an error.
import java.util.*;
public class Problem1 {
static int x =0;
static int counter = 0;
//input
public static void main(String[] args) {
Scanner scan = new Scanner (System.in);
String s= scan.nextLine();
System.out.println(recursive(s));
}
//recursive method
public static int recursive(String s){
if(s.length()==1){
x=(x*10)+ Integer.parseInt(s.substring(0,1));
return x;
}
else{
x = (x*10)+Integer.parseInt(s.substring(0,1));
counter++;
return recursive(s.substring(counter,s.length()-1));
}
}
}
import java.util.Scanner;
public class Problem1 {
static int x = 0;
static int counter = 0;
// input
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String s = scan.nextLine();
System.out.println(recursive(s));
}
// recursive method
public static int recursive(String s) {
if (s.length() == 1) {
x = (x * 10) + Integer.parseInt(s.substring(0, 1));
return x;
} else {
x = (x * 10) + Integer.parseInt(s.substring(0, 1));
counter++;
return recursive(s.substring(1, s.length()));
}
}
}
Look at your static counter variable. You are incrementing it every time. But you only want to have the substring starting at 1 (so cut off the first "letter").
So instead of using:
counter++;
return recursive(s.substring(counter,s.length()-1));
consider using:
return recursive(s.substring(1)); // you even don't really need the length
Because the String s parameter is as follows:
1st call: 1234567
2nd call: 234567
3rd call: 34567
4th call: 4567
...
So, you only have to cut off the first letter.
Btw: your sample "project" is a really funny one ;)
A few notes to start:
If you're doing recursion, you probably don't want to use a member variable. It's not wrong to do so, but not really typical of the pattern (your x variable).
It's often handy to pass in state through the recursion, although you wouldn't have to (that is, current value of x).
Your case is a little odd because you have to change your current parse value for every sub-parse (shifting by 10 each time); makes it a little more complicated.
If you are going to keep x as a member variable (which does seem to make sense in this case), you don't need to return anything from recursive.
Can you really not just use Integer.parseInt()?
Code could be much more simple, something like:
void recursive (String s)
{
if (s.length() == 0) return 0;
x = x * 10 + Integer.parseInt(s.substring(0, 1));
recursive(s.substring(1));
}
recursion("1234567", 0, 1)
The above code will turn the string "1234567" into an int using recursion. You must pass the string you want to convert, and then 0 and 1.
public static int recursion(String s, int result, int place) {
result += place * Integer.parseInt(s.charAt(s.length() - 1) + "");
if(s.length() == 1) {
return result;
}
else {
return recursion(s.substring(0, s.length() - 1), result, place * 10);
}
}
public static int computeStr(String str) {
if (str.equals("")) {
return 0;
}
int x = 1;
for (int i = 0; i < str.length() - 1; i++) {
x = x * 10;
}
x = x * Integer.parseInt(str.substring(0, 1));
return x + computeStr(str.substring(1));
}
For example: "2432" is (2 * 1000) + (4 * 100) + (3*10) + (2*1) = 2432
this algorithm begins at first position (2) from 2432
I know its kind of a late response but you could try something like this :-
private static int stringToInt(String string) {
if (string.length() == 0) {
return 0;
}
int rv;
int num = string.charAt(string.length() - 1) - '0';
String restOfTheString = string.substring(0, string.length() - 1);
rv = stringToInt(restOfTheString) * 10 + num;
return rv;
}
Try something like this:
Subtracting the ASCII code of the '0' character from your character returns an integer:
public class StringRecursion {
static int counter = 0;
public static void main(String[] args) {
System.out.println(convertStringToInt("123456"));
}
public static int convertStringToInt(String input) {
if (input.length() == 1)
return input.charAt(0) - '0';
int value = convertStringToInt(input.substring(0, input.length() - 1));
counter++;
return value * 10 + input.charAt(counter) - '0';
}
}
Try it like this :
public static int conStrToInt(String str) {
if(str.length()==0)
{
return 0;
}
char cc = str.charAt(0);
String ros = str.substring(1);
int factor=1;
for(int i=0;i<str.length()-1;i++)
factor*=10;
factor=factor*(cc-'0');
return factor+conStrToInt(ros);
}

java : better way of doing this than using if and else

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.

Is there an equivalent for toPrecision() in Java?

In porting an algorithm from JavaScript to Java, I've run into the problem that I need a replacement for JavaScript's toPrecision(). The problem is that I don't have a clue how small or large the numbers will be, so I can't use a simple NumberFormat with the right format.
Is there a standard class that offers a similar functionality?
EDIT
Here is what I came up with:
double toPrecision(double n, double p) {
if (n==0) return 0;
double e = Math.floor(Math.log10(Math.abs(n)));
double f = Math.exp((e-p+1)*Math.log(10));
return Math.round(n/f)*f;
}
In principle, it does the right thing, but rounding errors completely ruin it. For example,
toPrecision(12.34567, 3) returns 12.299999999999997
EDIT 2
This version works perfectly for 11 out of 12 test cases...
double toPrecision(double n, double p) {
if (n==0) return 0;
double e = Math.floor(Math.log10(Math.abs(n)));
double f = Math.round(Math.exp((Math.abs(e-p+1))*Math.log(10)));
if (e-p+1<0) {
f = 1/f;
}
return Math.round(n/f)*f;
}
But toPrecision(0.00001234567, 3) still returns 1.2299999999999999E-5 instead of 1.23E-5
Use BigDecimal and setScale() method to set the precision
BigDecimal bd = new BigDecimal("1.23456789");
System.out.println(bd.setScale(3,BigDecimal.ROUND_HALF_UP));
Output
1.235
See
IDEone demo
The simplest solution I came up with for this uses a combination of java.math.BigDecimal and java.math.MathContext like so.
String toPrecision(double number, int precision) {
return new BigDecimal(number, new MathContext(precision)).toString();
}
I'm using this in the dynjs implementation of Number.prototype.toPrecision.
Here's a java solution using String.format.
public static String toPrecision(double d, int digits) {
s = String.format("%."+((digits>0)?digits:16)+"g",d).replace("e+0","e+").replace("e-0","e-");
return s;
}
The .replace is only needed if you want to mimic javascript where it has no leading zero on exponents. If you are just using it for a rounding then return the value as
return Double.parseDouble(s);
Here is some unit test code:
public void testToPrecision() {
String s = NumberFormat.toPrecision(1234567.0,5);
assertEquals("1.2346e+6",s);
s = NumberFormat.toPrecision(12.34567,5);
assertEquals("12.346",s);
s = NumberFormat.toPrecision(0.1234567,5);
assertEquals("0.12346",s);
s = NumberFormat.toPrecision(0.1234567e20,5);
assertEquals("1.2346e+19",s);
s = NumberFormat.toPrecision(-0.1234567e-8,5);
assertEquals("-1.2346e-9",s);
s = NumberFormat.toPrecision(1.0/3.0,5);
assertEquals("0.33333",s);
s = NumberFormat.toPrecision(1.0/3.0,0);
assertEquals("0.3333333333333333",s);
}
You can use double with
double d = 1.23456789;
System.out.println(Math.round(d * 1e3) / 1e3);
prints
1.235
or
System.out.printf("%.3f%n", d);
does the same.
public static void main(String... args) {
System.out.println(round3significant(12345678.9));
System.out.println(round3significant(0.0000012345));
}
public static double round3significant(double d) {
if (d < 100) {
double divide = 1;
while(d < 100) {
d *= 10;
divide *= 10;
}
return Math.round(d) / divide;
} else {
double multi = 1;
while(d > 1000) {
d /= 10;
multi *= 10;
}
return Math.round(d) * multi;
}
}
prints
1.23E7
1.23E-6
You can use NumberFormat to only display as a decimal.
This finally works...
double toPrecision(double n, double p) {
if (n==0) return 0;
double e = Math.floor(Math.log10(Math.abs(n)));
double f = Math.round(Math.exp((Math.abs(e-p+1))*Math.log(10)));
if (e-p+1<0) {
return Math.round(n*f)/f;
}
return Math.round(n/f)*f;
}
import java.text.*;
Class Decimals
{
public static void main(String[] args)
{
float f = 125.069f;
DecimalFormat form = new DecimalFormat("#.##");
System.out.println(form.format(f));
}
}
.## represents upto what decimal places you want
I hope this suits your requirement.

Categories