Is there an equivalent for toPrecision() in Java? - 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.

Related

Its possible to define class as double type java?

I have the following class in java :
public class Percentage
{
private double n;
Percentage (double n )
{
this.n=n;
}
public void setN()
{
this.n=n;
}
public double getN()
{
return n;
}
public double percntage ()
{
return this.n/100;
}
}
this Class Percentage will return a double value, but the problem is we can't make any mathematic operation with values like below:
public static void main (String args[])
{
Percentage p = new Percentage(5);
double b=1;
b=p*12; // this is error because the class Percentage in not of type double
}
is there someway to make Percentage of type double ?
That is an error because you are multiplying the Percentage object with double value.
The alternative is
public static void main (String args[])
{
Percentage p = new Percentage(5);
double b=1;
b=p.getN()*12;
}
You cannot make the class type double. You can perform your operation in the n value instead.
b = p.getN()*12;
you can't define a class as double, because double is a primitive type. What you can do is what the others user suggested:
p.getN();
It will return the double value you need.
No, you can't make it behave like a double, but (like BigDecimal) you can supply methods for performing the relevant operations.
Since your code seems to imply that n = 10 means 10%, i.e. a factor of 0.10, you could make methods like these:
public double of(double value) {
return value * this.n / 100d;
}
public double add(double value) {
return value * (100d + this.n)) / 100d;
}
and then use it like this:
Percentage p = new Percentage(10);
double input = 55;
double d1 = p.of(input); // 10% of 55 = 5.5
double d2 = p.add(input); // 55 + 10% = 60.5

DecimalFormats and Return statements

For my college class, I have to create a program that calculates the midpoint on a line. I have most of the core program worked out, but I need some help.
public double calculateMidpointX() { // acessor
xmid = (calcX1 + calcX2) / 2.0;
return (xmid);
}
...
DecimalFormat num = new DecimalFormat("###.##");
How do I return xmid with the DecimalFormat("###.##");
Is there a specific syntax I need to be looking at? What if I used System.out.println?
public static void main(String[] args)
{
System.out.println(calculateMidpointX(1.373,3)); // Print 2.19
}
public static double calculateMidpointX(double x, double y) {
DecimalFormat num = new DecimalFormat("###.##");
Double xmid = (x + y) / 2.0;
return (Double.parseDouble(num.format(xmid))); // This return 2.19
}
If i only use return xmid; without format it, it will return 2.1865.

Java: convert floating point binary to floating point decimal

I want to convert a string representing the mantissa portion of a IEEE754 double.
Cannot find if there is such a conversion method in Java, in order to avoid manually adding 1 + 1/2 + 1/4 + 1/8 etc.
|0100000011001010000111110000000000000000000000000000000000000000 --> 13374 in IEEE754
|------------1010000111110000000000000000000000000000000000000000 --> mantissa part
| 1.1010000111110000000000000000000000000000000000000000 --> restoring fixed value 1
String s = "1.1010000111110000000000000000000000000000000000000000"
double mant10 = Double.readFromFloatBinary(s); // does such method exists in Java?
Yes, there are ways to read from a binary representation. But you don't have a representation in an IEEE format.
I would ignore the period and read as a BigInteger base2, then create a value to divide by also using BigInteger:
private static double binaryStringToDouble(String s) {
return stringToDouble(s, 2);
}
private static double stringToDouble(String s, int base) {
String withoutPeriod = s.replace(".", "");
double value = new BigInteger(withoutPeriod, base).doubleValue();
String binaryDivisor = "1" + s.split("\\.")[1].replace("1", "0");
double divisor = new BigInteger(binaryDivisor, base).doubleValue();
return value / divisor;
}
#Test
public void test_one_point_5() {
String s = "1.1";
double d = binaryStringToDouble(s);
assertEquals(1.5, d, 0.0001);
}
#Test
public void test_6_8125() {
String s = "110.1101";
double d = binaryStringToDouble(s);
assertEquals(6.8125, d, 0.0001);
}
#Test
public void test_yours() {
String s = "1.1010000111110000000000000000000000000000000000000000";
double d = binaryStringToDouble(s);
assertEquals(1.632568359375, d, 0.000000000000000001);
}
#Test
public void test_yours_no_trailing_zeros() {
String s = "1.101000011111";
double d = binaryStringToDouble(s);
assertEquals(1.632568359375, d, 0.000000000000000001);
}

need to get original double data from NumberFormatted double

I need percentage form of a double value, so I used NumberFormat
double d = 0.13;
NumberFormat nf = NumberFormat.getPercentInstance();
String kpr = nf.format(kpr);
I saved this property to an object Person through setter. When I get it back through getter method it returns String(of course).
Is there a way to de-format this String to double value as 0.13, so that I can perform arithmetics on it?
public static void main(String s[]) {
getDoubleFromStringWithPercent("12345%");
}
private static Double getDoubleFromStringWithPercent(String string) {
Locale locale = Locale.CANADA;
Double num = null;
try {
Number number = NumberFormat.getPercentInstance(locale).parse(string);
if (number instanceof Long) {
num = ((Long) number).doubleValue();
} else {
num = (Double) number;
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
return num;
}
Locale need for find decimal delimiter ("." or ",");
Alternative version:
String string ="2165%";
double d = Double.parseDouble(string.substring(0, string.length()-1));
if (d != 0) {
d = d / 100;
}
double d=(Double.parase(kpr.substring(kpr.length-1)))/100;

How to get the length of a numbers fraction part?

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

Categories