Floating point errors - java

I am having trouble with floating points. A the double . 56 in Java, for example, might actually be stored as .56000...1.
I am trying to convert a decimal to a fraction. I tried to do this using continued fractions
Continuous Fractions
but my answers using that method were inaccurate due to how to computer stored and rounded decimals.
I tried an alternative method:
public static Rational rationalize(double a){
if(a>= 1){
//throw some exception
}
String copOut = Double.toString(a);
int counter = 0;
System.out.println(a);
while(a%1 != 0 && counter < copOut.length() - 2){
a *= 10;
counter++;
}
long deno = (long)Math.pow(10,counter);//sets the denominator
Rational frac = new Rational((long)a,deno)//the unsimplified rational number
long gcd = frac.gcd();
long fnum = frac.getNumer();//gets the numerator
long fden = frac.getDenom();//gets the denominator
frac = new Rational(fnum/gcd, fden/gcd);
return frac;
}
I am using the string to find the length of the decimal to determine how many time I should multiply by 10. I later truncate the decimal. This gets me the right answer, but it does not feel like the right approach?
Can someone suggest the 'correct' way to do this?

Actually you are doing great.. But this will fail if the Input is something about 11.56. Here you need to to do copOut.length() - 3.
To make it dynamic use String#split()
String decLength = copOut.split("\\.")[1]; //this will result "56" (Actual string after decimal)
Now you just need to do only
while(a%1 != 0 && counter < decLength.length()){
a *= 10;
counter++;
}
If you want to remove the loop then use
long d = (long)Math.pow(10,decLength.length());
a=a*d;

Related

value not displaying the right result

When I use numbers such as the one store in decimal the output just starts showing weird answers
this is my code
public static void main(String[] args) {
long decimal =444444;
long count = 0;
long a = 0;
long b = 0;
while(decimal != 0)
{
a = decimal%2;
b += a* Math.pow(10, count);
count++;
decimal = decimal/2;
}
System.out.print(b);
}
this is the output that it prints 1101100100000011136 when the right output should be 1101100100000011100 for decimal 444444
now when I input 123456 it prints 11110001001000000 which is right
I must use long for this and without using strings so that is the code that I'm using but I can't find a way to fix it since mathematically it seems to work.
edit: the goal of the code is to display the binary representation of the decimal in called "decimal" without using string or arrays
It because the maximum number a long can hold is 9,223,372,036,854,775,807(I get this from Long.MAX_VALUE) and your b after loop for a while it exceeds that maximum value and cannot hold correct value anymore. there for you will have some unexpected result. So with long type, I'm afraid that your function only corrects with a small value.
UPDATE
Since you don't use array or String to hold the binary result, you can use BigInteger to store the value of binary, it can hold more than long.
As what the other answers has pointed out, you can generate the output into a string instead as follows.
long decimal = 444444;
long a = 0;
String result = "";
while ( decimal != 0 )
{
a = decimal % 2;
result = Long.toString( a ) + result;
decimal = decimal / 2;
}
System.out.print( result );

How to move the digit in a double to the end without converting to string in Java

I am trying to make my number move the first character to the end.
For example I would have my double d.
double d = 12345.6;
double result = 2345.61;
Currently I am removing the first character of d with:
d = d % (int) Math.pow(10, (int) Math.log10(d));
But I do not know how to store the character I am removing so I could put it at the end. I know I could just convert d into an array or a string, but I want to keep it as a double if at all possible.
I am getting my double from a nanosecond clock using Instant.now, so I can guarantee it starts as an 8 digit positive int, which I start by adding .0 to so I can make it a double. I know I can just use string (as I mentioned in the post), but I was wondering if there was a way to do it without conversions.
Thanks for helping!
(this is my first post I apologize if it is bad)
This is a pretty tough problem, and this isn't a working answer but it is pretty close. The only trouble I ran into was java adding decimals to the end of my doubles because it can't represent a number very well. My solution might get you on the right path. The appendChar was messing up because it was adding digits to the end of the double, other than that problem this would have worked.
public static void main(String[] args) {
double test = 4234.1211;
boolean hasDecimals = test % 1 > 0;
double[] leadChar = getLeadDigitAndMulti(test);
double appendedValue = appendLeadChar(test, (int) leadChar[1], hasDecimals);
}
public static double[] getLeadDigitAndMulti(double value) {
double[] result = new double[2];
int multiplier = 10;
int currentMultiplier = 1;
while (value > currentMultiplier) {
currentMultiplier *= multiplier;
}
currentMultiplier /= multiplier;
double trail = value % (currentMultiplier);
result[0] = currentMultiplier;
double lead = value - trail;
lead /= currentMultiplier;
result[1] = lead;
return result;
}
public static double appendLeadChar(double value, int leadChar, boolean hasDecimals) {
if (!hasDecimals) {
return (value * 10) + leadChar;
}
int multiplier = 10;
double currentMultiplier = 1;
while (value > 0) {
value %= currentMultiplier;
currentMultiplier = currentMultiplier / multiplier;
}
return 0;
}
I would start with at least figuring out how many digits long your double is. I'm not too sure of how to make it work but I saw another question that would answer it. Here is the link to that thread:
Number of decimal digits in a double
And the closest code on there that I could find to find the length would be:
double d= 234.12413;
String text = Double.toString(Math.abs(d));
int integerPlaces = text.indexOf('.');
int decimalPlaces = text.length() - integerPlaces - 1;
NOTE THIS SEGMENT OF CODE IS NOT MINE, credit goes to Peter Lawrey who originally answered this in the linked thread.
Then using code or modified code similar to above ^ assuming you would find how to find the length of the double or the total number of digits of your double, you would create a new int or double variable that would store the double and round it using BigDecimal to the highest place value. The place that the BigDecimal will round to will be set using a 10*pow(x) where x is the number of places AFTER the decimal.
Sorry I am unable to provide code on how to make this actually run because I am pretty new to java. Here is what I mean in more detailed pseudocode:
double d = 12345.6; //the double you are evaluating
double dNoDecimal; //will be rounded to have no decimal places in order to calculate place of the 1st digit
double dRoundedFirstDigit; //stores the rounded number with only the 1st digit
double firstDigit; //stores first digit
dNoDecimal = d; //transfers value
dNoDecimal = [use BigDecimal to round so no decimal places will be left]
//dNoDecimal would be equal to 12345 right now
[use above code to find total amount of place values]
[knowing place values use BigDecimal to round and isolate 1st digit of double]
dRoundedFirstDigit = dNoDecimal; //transfers value
dRoundedFirstDigit = [round using BigDecimal to leave only 1st digit]
firstDigit = [dRoundedFirstDigit cut down to 1st digit value using length found from before, again an equation will be needed]
//Now use reverse process
//do the same thing as above, but find the number of decimals by rounding down to leave only decimals (leaving only .6)
//find the length
//use length to calculate what to add to the original value to move the digit to the end (in this case would be d += firstDigit*Math.pow(10,-2))
I apologize if I just made everything seem more confusing, but I tried my best, hope this helps.
Also, doing this without an array or string is really difficult... may I ask why you need to do it without one?

Get a numer decimal part as Integer using only math

Edit: This has to do with how computers handle floating point operations, a fact that every programmer faces once in a lifetime. I didn't understand this correctly when I asked the question.
I know the simplest way to start dealing with this would be:
val floatNumber: Float = 123.456f
val decimalPart = floatNumber - floatNumber.toInt() //This would be 0.456 (I don't care about precision as this is not the main objective of my question)
Now in a real world with a pen and a piece of paper, if I want to "convert" the decimal part 0.456 to integer, I just need to multiply 0.456 * 1000, and I get the desired result, which is 456 (an integer number).
Many proposed solutions suggest splitting the number as string and extracting the decimal part this way, but I need the solution to be obtained mathematically, not using strings.
Given a number, with an unknown number of decimals (convert to string and counting chars after . or , is not acceptable), I need to "extract" it's decimal part as an integer using only math.
Read questions like this with no luck:
How to get the decimal part of a float?
How to extract fractional digits of double/BigDecimal
If someone knows a kotlin language solution, it would be great. I will post this question also on the math platform just in case.
How do I get whole and fractional parts from double in JSP/Java?
Update:
Is there a "mathematical" way to "calculate" how many decimals a number has? (It is obvious when you convert to string and count the chars, but I need to avoid using strings) It would be great cause calculating: decimal (0.456) * 10 * number of decimals(3) will produce the desired result.
Update 2
This is not my use-case, but I guess it will clarify the idea:
Suppose you want to calculate a constant(such as PI), and want to return an integer with at most 50 digits of the decimal part of the constant. The constant doesn't have to be necessarily infinite (can be for example 0.5, in which case "5" will be returned)
I would just multiply the fractional number by 10 (or move the decimal point to the right) until it has no fractional part left:
public static long fractionalDigitsLong(BigDecimal value) {
BigDecimal fractional = value.remainder(BigDecimal.ONE);
long digits;
do {
fractional = fractional.movePointRight(1); // or multiply(BigDecimal.TEN)
digits = fractional.longValue();
} while (fractional.compareTo(BigDecimal.valueOf(digits)) != 0);
return digits;
}
Note 1: using BigDecimal to avoid floating point precision problems
Note 2: using compareTo since equals also compares the scale ("0.0" not equals "0.00")
(sure the BigDecimal already knows the size of the fractional part, just the value returned by scale())
Complement:
If using BigDecimal the whole problem can be compressed to:
public static BigInteger fractionalDigits(BigDecimal value) {
return value.remainder(BigDecimal.ONE).stripTrailingZeros().unscaledValue();
}
stripping zeros can be suppressed if desired
I am not sure if it counts against you on this specific problem if you use some String converters with a method(). That is one way to get the proper answer. I know that you stated you couldn't use String, but would you be able to use Strings within a Custom made method? That could get you the answer that you need with precision. Here is the class that could help us convert the number:
class NumConvert{
String theNum;
public NumConvert(String theNum) {
this.theNum = theNum;
}
public int convert() {
String a = String.valueOf(theNum);
String[] b = a.split("\\.");
String b2 = b[1];
int zeros = b2.length();
String num = "1";
for(int x = 0; x < zeros; x++) {
num += "0";
}
float c = Float.parseFloat(theNum);
int multiply = Integer.parseInt(num);
float answer = c - (int)c;
int integerForm = (int)(answer * multiply);
return integerForm;
}
}
Then within your main class:
public class ChapterOneBasics {
public static void main(String[] args) throws java.io.IOException{
NumConvert n = new NumConvert("123.456");
NumConvert q = new NumConvert("123.45600128");
System.out.println(q.convert());
System.out.println(n.convert());
}
}
output:
45600128
456
Float or Double are imprecise, just an approximation - without precision. Hence 12.345 is somewhere between 12.3449... and 12.3450... .
This means that 12.340 cannot be distinghuished from 12.34. The "decimal part" would be 34 divided by 100.
Also 12.01 would have a "decimal part" 1 divided by 100, and too 12.1 would have 1 divided by 10.
So a complete algorith would be (using java):
int[] decimalsAndDivider(double x) {
int decimalPart = 0;
int divider = 1;
final double EPS = 0.001;
for (;;) {
double error = x - (int)x;
if (-EPS < error && error < EPS) {
break;
}
x *= 10;
decimalPart = 10 * decimalPart + ((int)(x + EPS) % 10);
divider *= 10;
}
return new int[] { decimalPart, divider };
}
I posted the below solution yesterday after testing it for a while, and later found that it does not always work due to problems regarding precision of floats, doubles and bigdecimals. My conclusion is that this problem is unsolvable if you want infinite precision:
So I re-post the code just for reference:
fun getDecimalCounter(d: Double): Int {
var temp = d
var tempInt = Math.floor(d)
var counter = 0
while ((temp - tempInt) > 0.0 ) {
temp *= 10
tempInt = Math.floor(temp)
counter++
}
return counter
}
fun main(args: Array <String> ) {
var d = 3.14159
if (d < 0) d = -d
val decimalCounter = getDecimalCounter(d)
val decimalPart = (d - Math.floor(d))
var decimalPartInt = Math.round(decimalPart * 10.0.pow(decimalCounter))
while (decimalPartInt % 10 == 0L) {
decimalPartInt /= 10
}
println(decimalPartInt)
}
I dropped floats because of lesser precision and used doubles.
The final rounding is also necessary due to precision.

How can you check if a specific integer occurs in a double?

Here are the specifics.
Say I have an integer 3.
How can I determine if 3 occurs in the any of the decimal places of a double. Say 0.098734. I understand you can cast the double as a String and then search the string, but is there a way to do it with modulus or some other means?
A double has is not exact and the difference to the next double varies.
So consider that a double has at most a precision of ca 17 digits, then:
boolean hasDecimalDigit(double x, int digit) {
if (x < 0) {
x = -x;
}
for (int i = 0; i < 17; ++i) {
x *= 10;
if (((int)x) % 10) == digit) {
return true;
}
}
return false;
}
This may very well be not in concordance with the String representation,
which often is a bit beautified.
Also there are limitations, overflow. Taking first modulo 1 may diminish some effects, but even taken modulo already may introduce garbage precision for huge numbers.
For maintaining a precision use BigDecimal as in:
BigDecimal x = new BigDecimal("0.098734");
This gives an exact fixed-point math with precision.
Convert to a string (like you'd do when printing it out) and then do a charAt or indexOf comparison

How do I parse non-integer octals in Java?

This may not be possible, but I figured it can't hurt to ask.
I have a program that needs to convert non-integer decimals into octal notation. From what I can tell, Java can only handle integer octals automatically. I've cobbled together something of a kludge, which involves breaking down the number into powers of eight, something like this.
.abcd = x * (1/8) + y * (1/64) + z * (1/512) + ......
which would be displayed as "0.xyz", if that makes any sense. The problem is, this is resulting in a lot of rounding/truncation errors for long numbers. Is there a better way to do this?
(edit)
Here's the algorithm I've been using to process the digits to the right of the decimal point:
double floatPartNum = Double.parseDouble("0." + temps[1]);
if (floatPartNum > 0) {
int p = 1;
result = result + ".";
while (floatPartNum > 0 && p < 16) {
double scale = 1/(Math.pow(8, p));
int modT = (int)( floatPartNum / scale );
result = result + modT;
double modScale = (double)modT * scale;
floatPartNum -= modScale;
p++;
}
}
I know of no floating point or fixed point support for octal numbers in base Java. If you show your algorithm for extracting the octal digits from the decimal, maybe we could help reduce the error.
There are some methods in the Float and Double classes that allow you to get the bit-wise representation of the number; for example Double.doubleToLongBits(double).
You could then extract the mantissa and exponent parts from the double-as-bits, and convert them to your octal format with no loss of precision.
However, it might be simpler to just fix your current algorithm. I'd have thought that you should be able to implement your approach without loss of precision. (Have you considered the possibility that the precision has already been lost; i.e. in the processes / calculations that produced your numbers in the first place?)
Your p < 16 is artificially truncating your output. When I try your code on 1.0/3.0, I get 0.252525252525252, but there's actually enough precision in the double to add three more octal digits, yielding 0.252525252525252525, if you change that to p < 20. But if you're concerned about "long numbers", then you might find that double just isn't big enough for your needs.
By the way, your loop can be simplified significantly, to:
for(int p = 1; floatPartNum > 0 && p < 20; ++p)
{
floatPartNum *= 8.0;
result = result + (int)floatPartNum;
floatPartNum -= (int)floatPartNum;
}
(tested), which eliminates all the need for Math.pow and so on. (Math.pow works by performing logarithms and exponentiations; it's overkill, and potentially roundoff-prone, when you're just multiplying by eight.)
How about something more like this?:
String result = "";
double floatPartNum = temps[1];
if( floatPartNum > 0 )
{
int p = 1;
result = result + ".";
while( floatPartNum > 0 && p < 16 )
{
floatPartNum *= 8.0D;
int modT = (int)floatPartNum;
floatPartNum -= modT;
result = result + modT;
p++;
}
}
Much fewer operations to introduce errors. (I am sorry I can't test this code before posting it, I am not near my programming tools.)

Categories