how to validate float against specific format in java? - java

I want to validate the float type data. I get the rules defined as
int precision1 = 3;
int precision2 = 2;
The above rule indicates the data format should be of 999.99
The expected validation of 1234.56, should fail from the above rule.
Also expected validation should fail for float 123.456 from the above rule.
Expected validation of 123.33 should be successful.
Any thoughts would be appreciated on validation process.
Thanks,
Kaygee

Quick and dirty:
int precision1 = 3;
int precision2 = 2;
float var = 123.12f;
String varStr = String.valueOf(var);
if (varStr.length() == (precision1 + precision2 + 1) && varStr.indexOf(".") == precision1) {
System.out.println(true);
} else {
System.out.println(false);
}

The user inputs a String, it is converted somewhere to float, and you try to validate the float. You can't do it like that.
The String representation of a float is a human artifact. Plus, a float tends to only approximate (very closely) the value of a converted String.
If you want to validate the precision the only way to go is to validate the user input String. And store it like a String if you want to keep the precision.
If you need a number, for instance to compute with, use a BigDecimal. It is designed to keep the precision exactly as given (important for financial calculations). They are not very nice to work with, but that's the price you pay if you want exact non-integer values.
EDIT
How to use a BigDecimal.
BigDecimal b1 = new BigDecimal("1234.23");
System.out.println(b1 + " scale was " + b1.scale()); 2
BigDecimal b2 = new BigDecimal("1234.523536223");
System.out.println(b2 + " scale was " + b2.scale()); // 9
You can obviously test the "precision" by using the scale. If b1.scale() == 2 || b1.scale() == 3 => valid.

Related

How to assertEquals on a value that is passed in as a String against a value which is a double or float

My method is as follows:
public void variable_equal_to_ratio_of_and(String exp, String numerator, String denominator) {
double numerTotal = 0, denomTotal = 0;
String[] numerArray = numerator.split(",");
String[] denomArray = denominator.split(",");
System.out.println("PCT value " + exp);
for (String iterator: numerArray) {
numerTotal += Double.valueOf(iterator);
}
for (String iterator: denomArray) {
denomTotal += Double.valueOf(iterator);
}
double ratio = (numerTotal * 100) / (numerTotal + denomTotal);
ratio = ratio / 100;
BigDecimal bd = new BigDecimal(ratio).setScale(3, RoundingMode.HALF_DOWN);
double d = bd.doubleValue();
org.junit.Assert.assertEquals(Float.valueOf(exp), d, 0);
}
To figure out what the actual value should be for this ratio our customers view, I need to do some math to get the answer and store that answer in a double or float which is what you're seeing in this method. The problem is I then have to do an assert equals on what our test framework pulls from the API and there is no valid method to compare a float/double with a string for junit.Assert. I seem to be able to convert the String passed in to a float/double, but then both the expected value and actual value has to be the same number of decimal places or the assertion fails.
When I convert the expected value to two decimals, it seems to always be done by DecimalFormat or BigDecimal and neither of those I can pass into the assertion.
I can convert the expected value string to 2 decimals, but then when I pass it into the AssertEquals as a double/float, it parses it to as many decimals as it wants.
The developers coded the ratio in GoLang as Math.round(((123.54999) * 10) / 10); and tell me it's using this formula: "float32((float64(float32(number1) * 100 / float32(number2))) / 100)"
But, my QA lead has written our entire testing framework in Java.
How can I keep the expected value passed to the assertion as the same number of decimals that I've set the actual value to in BigDecimal?
To assert that 2 floating-point values are equal to some number of decimal places, you can change the epsilon parameter on assertEquals (the 3rd value)
For example,
Assert.assertEquals(Float.valueOf(exp), d, .01);
would assert that Float.valueOf(exp) and d are equivalent with an epsilon of .01.

Convert double to int without loss of precision in java

I would like to convert a double (for example price with a value of 1.90) to an integer without losses! I am making a program that processes money, and I have to input them as doubles, and then convert them to integers so that I can proccess them and for example when I have 1.90 euros and i want to convert it to cents it will appear as 189 cents instead of 190! please help me :) thanks in advance
Check the details on how doubles and floats behave in java in the JLS
Well, you could round the value to desired precision. As long as you're within given format's precision (~15 digits for double ~7 for float) you'll get good results.
double fractValue = 1.90; // 1.8999999....
int val = (int)Math.round(fractValue*100);
It's much better idea to use BigDecimal though. You will never lose any precision then.
double x = 1.89; //Or whatever
String[] y = String.valueOf(x).split("[.]"); // Returns array having 1 and 89
String z = y[0] + y[1]; //String which is = 189
if(y[1].length()==1)
z +="0"; // Add a 0 in end if required
int finalInt = Integer.parseInt(z); //Convert String to Integer
finalInt should be what you want.

Can you replicate the Floor function found in Excel in Java?

I have searched the internet but have not found any solutions for my question.
I would like to be able to use the same/replicate the type of FLOOR function found in Excel in Java. In particular I would like to be able to provide a value (double or preferably BigDecimal) and round down to the nearest multiple of a significance I provide.
Examples 1:
Value = 24,519.30235
Significance = 0.01
Returned Value = 24,519.30
Example 2:
Value = 76.81485697
Significance = 1
Returned Value = 76
Example 3:
Value = 12,457,854
Significance = 100
Returned Value = 12,457,800
I am pretty new to java and was wondering if someone knew if an API already includes the function or if they would be kind enough to give me a solution to the above. I am aware of BigDecimal but I might have missed the correct function.
Many thanks
Yes you can.
Lets say given numbers are
76.21445
and
0.01
what you can do is multiply 76.21445 by 100 (or divide per 0.01)
round the result to nearest or lower integer (depending which one you want)
and than multiply it by the number again.
Note that it may not exactly print what you want if you will not go for the numbers with decimal precision. (The problem of numbers which in the binary format are not finite in extansion). Also in Math you have the round function taking doing pretty much what you want.
http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html you use it like this
round(200.3456, 2);
one Example Code could be
public static void main(String[] args) {
BigDecimal value = new BigDecimal("2.0");
BigDecimal significance = new BigDecimal("0.5");
for (int i = 1; i <= 10; i++) {
System.out.println(value + " --> " + floor(value, significance));
value = value.add(new BigDecimal("0.1"));
}
}
private static double floor(BigDecimal value, BigDecimal significance) {
double result = 0;
if (value != null) {
result = value.divide(significance).doubleValue();
result = Math.floor(result) * significance.doubleValue();
}
return result;
}
To round a BigDecimal, you can use setScale(). In your case, you want RoundingMode.FLOOR.
Now you need to determine the number of digits from the "significance". Use Math.log10(significance) for that. You'll probably have to round the result up.
If the result is negative, then you have a significance < 1. In this case, use setScale(-result, RoundingMode.FLOOR) to round to N digits.
If it's > 1, then use this code:
value
.divide(significance)
.setScale(0, RoundingMode.FLOOR)
.multiply(significance);
i.e. 1024 and 100 gives 10.24 -> 10 -> 1000.

Nicest way to solve stringified floating rounding issue through algorithm? (Java, JEval)

I have an output operation from JEval that is an string with the float imprecision, something like "1.56700000001". I need some approach to hold the maximum precision but correcting the float imprecision. Perhaps some efficient algorithm that makes the most exact thing without being wrong.
If I´m not wrong, any double with not exact binary representation will be output´d if so in a String of length() 18, with the precision = (14 minus - point char - integer part).
So we can round to the precision-1 (last) digit when the string is clearly using all the bits without trailing zeroes (as JEval dont show them, this means when length() == 18 ).
The only problem would be if the original string has a real expected full value and needs not rounding, in that case we only would loose one digit of precision.
What do you think of this approach. Is it a better way?
For example:
import java.math.BigDecimal;
import java.math.MathContext;
public class test {
private final static int THREESHOLD = 3; // num of decimals from which
// we consider that they represent a floating
// representation inaccuracy in case every double´s
//digit is used with no traliing zeroes ending
public static void main(String[] args){
String[] JEvalOutput = {"1.5555000000000001", //Rounding is needed
"234455555.29", //Rounding is not needed
"455656.45599999998", //Rounding is needed
"111132323232334.19", //Here there is a problem, should be rounded???
//Thats why we use THREESHOLD var, to distinguish when can we consider
"123456789012345678"};//Rounding is not needed
for (String aux : JEvalOutput){
int precision = aux.length()-(aux.contains(".")?1:0);
if (precision==17 && aux.contains(".") && aux.length()-aux.indexOf('.')-1 >THREESHOLD) precision--;
BigDecimal a = new BigDecimal(aux, new MathContext(precision)).stripTrailingZeros();
System.out.println(aux + " --> " + a.toPlainString()); //Only First and Third are rounded.
}
}
}
Prints:
1.5555000000000001 --> 1.5555
234455555.29 --> 234455555.29
455656.45599999998 --> 455656.456
111132323232334.19 --> 111132323232334.19 //If THREESHOLD was 1, then this would be 111(...)34.2
123456789012345678 --> 123456789012345678
Is there any cleaner, best practice, professional solution?
This is what you want. You're welcome.
BigDecimal bd = new BigDecimal("123.4566661");
DecimalFormat df = new DecimalFormat("#.0#");
System.out.println(df.format(bd));

Calculating remainder of two doubles in java

I have the following code :
Double x = 17.0;
Double y = 0.1;
double remainder = x.doubleValue() % y.doubleValue();
When I run this I get remainder = 0.09999999999999906
Any idea why??
I basically need to check that x is fully divisible by y. Can you suggest alternative ways to do that in java.
Thanks
Because of how floating-point numbers are represented.
If you want exact values, use BigDecimal:
BigDecimal remainder = BigDecimal.valueOf(x).remainder(BigDecimal.valueOf(y));
Another way to to that is to multiple each value by 10 (or 100, 1000), cast to int, and then use %.
You need to compare your result which allows for rounding error.
if (remainder < ERROR || remainder > 0.1 - ERROR)
Also, don't use Double when you mean to use double
Expecting precise results from double arithmetic is problematic on computers. The basic culprit is that us humans use base 10 mostly, whereas computers normally store numbers in base 2. There are conversion problems between the two.
This code will do what you want:
public static void main(String[] args) {
BigDecimal x = BigDecimal.valueOf(17.0);
BigDecimal y = BigDecimal.valueOf(0.1);
BigDecimal remainder = x.remainder(y);
System.out.println("remainder = " + remainder);
final boolean divisible = remainder.equals(BigDecimal.valueOf(0.0));
System.out.println("divisible = " + divisible);
}

Categories