How do I parse non-integer octals in Java? - 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.)

Related

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.

Performing way to limit double accuracy

I want manage numbers on a range from:
from 0,001 to 999,999
For representation reasons, I want to drop some of the accuracy keeping only the 3 most important digits of the number.
For the number 123,12 I expect the result 123.
For the number 12,123 I expect the result 12,1.
For the number 0,001 I expect the result 0,001.
The best solution I thought of is transforming the number into a String, and back again to double, this way:
number = number*1000;
String s = new String(number);
s = s.substr(0, 3) + "000";
number = Double.parseDouble(s);
number = number/1000;
This does the job but it looks both poorly performing and not elegant.
Any more clever alternative?
Thank you!
Here's a somewhat-convoluted answer that doesn't require the use of any conversion to String:
final int numDigits = 3;
double d = 12.123;
int counter;
for (counter = 0; counter < numDigits && d < Math.pow(10, numDigits - 1); counter++) {
d *= 10;
}
d = Math.floor(d);
d /= Math.pow(10, counter);
System.out.println(d);
Output: 12.1
Essentially it multiplies the double by 10 until it reaches the largest value under 1000 (your maximum value is 999.999), keeping track of how many times it has been multiplied. It then performs the floor function to get rid of any precision to the right of the decimal point. Finally, we divide the number by 10, counter times, which provides us with the first 3 significant figures.
Perhaps use this RegEx to make the code more concise?
^[,0]{0,6}(\d{3}|\d{2},\d|\d,\d{2})

Floating point errors

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;

Calculating Eulers Totient Function for very large numbers JAVA

I've managed to get a version of Eulers Totient Function working, albeit one that works for smaller numbers (smaller here being smaller compared to the 1024 bit numbers I need it to calculate)
My version is here -
public static BigInteger eulerTotientBigInt(BigInteger calculate) {
BigInteger count = new BigInteger("0");
for(BigInteger i = new BigInteger("1"); i.compareTo(calculate) < 0; i = i.add(BigInteger.ONE)) {
BigInteger check = GCD(calculate,i);
if(check.compareTo(BigInteger.ONE)==0) {//coprime
count = count.add(BigInteger.ONE);
}
}
return count;
}
While this works for smaller numbers, it works by iterating through every possible from 1 to the number being calculated. With large BigIntegers, this is totally unfeasible.
I've read that it's possible to divide the number on each iteration, removing the need to go through them one by one. I'm just not sure what I'm supposed to divide by what (some of the examples I've looked at are in C and use longs and a square root - as far as I know I can't calculate an accurate an accurate square root of a BigInteger. I'm also wondering that if for modular arithmetic such as this, does the function need to include an argument stating what the mod is. I'm totally unsure on that so any advice much appreciated.
Can anyone point me in the right direction here?
PS I deleted this question when I found modifying Euler Totient Function. I adapted it to work with BigIntegers -
public static BigInteger etfBig(BigInteger n) {
BigInteger result = n;
BigInteger i;
for(i = new BigInteger("2"); (i.multiply(i)).compareTo(n) <= 0; i = i.add(BigInteger.ONE)) {
if((n.mod(i)).compareTo(BigInteger.ZERO) == 0)
result = result.divide(i);
while(n.mod(i).compareTo(BigInteger.ZERO)== 0 )
n = n.divide(i);
}
if(n.compareTo(BigInteger.ONE) > 0)
result = result.subtract((result.divide(n)));
return result;
}
And it does give an accurate result, bit when passed a 1024 bit number it runs forever (I'm still not sure if it even finished, it's been running for 20 minutes).
There is a formula for the totient function, which required the prime factorization of n.
Look here.
The formula is:
phi(n) = n * (p1 - 1) / p1 * (p2 - 1) / p2 ....
were p1, p2, etc. are all the prime divisors of n.
Note that you only need BigInteger, not floating point, because the division is always exact.
So now the problem is reduced to finding all prime factors, which is better than iteration.
Here is the whole solution:
int n; //this is the number you want to find the totient of
int tot = n; //this will be the totient at the end of the sample
for (int p = 2; p*p <= n; p++)
{
if (n%p==0)
{
tot /= p;
tot *= (p-1);
while ( n % p == 0 )
n /= p;
}
}
if ( n > 1 ) { // now n is the largest prime divisor
tot /= n;
tot *= (n-1);
}
The algorithm you are trying to write is equivalent to factoring the argument n, which means you should expect it to run forever, practically speaking until either your computer dies or you die. See this post in mathoverflow for more information: How hard is it to compute the Euler totient function?.
If, on the other hand, you want the value of the totient for some large number for which you have the factorization, pass the argument as sequence of (prime, exponent) pairs.
The etfBig method has a problem.
Euler's product formula is n*((factor-1)/factor) for all factors.
Note: Petar's code has it as:
tot /= p;
tot *= (p-1);
In the etfBig method, replace result = result.divide(i);
with
result = result.multiply(i.subtract(BigInteger.ONE)).divide(i);
Testing from 2 to 200 then produces the same results as the regular algorithm.

Print on last iteration of for loop

So I have a simple for loop:
double bg = 5.0;
double f = 0.0;
for(double i = 0; i <= bg; i += 1)
{
f = f + ((2 * i + 1)*0.1);
if(i == bg)
{
System.out.printf ("%.1f" , f);
}
}
When I increment i with 1 for each itiration it works fine.
But when i do i += 0.1 it doesn't print f.
Any ideas why?
You can not compare floats like that.
Usually equality of two floats(doubles) is checked with something like
if (Math.abs(i - bg) < 0.00001f) //0.00001f is very small value - almost zero, pick this value to suit your needs
For more look at http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
Your code should look like
double bg = 5.0;
double f = 0.0;
for(double i = 0; i <= bg; i += 1)
{
f = f + ((2 * i + 1)*0.1);
if (Math.abs(i - bg) < 0.00001f)
{
System.out.printf ("%.1f" , f);
}
}
Floating-point numbers don't have exact representations for all the numbers you think they might. For example, when dividing 1 by 3, you get 0.333... since you use decimal numeric system.
However, computers use binary, so even though 0.1 seems like an easy and exact number to write, in binary it looks more like 0.0001100011..., and so on to infinity. And, since computers don't have infinite memory, this number is rounded to the closest possible representation. That's why the exact comparison does not work.
There are a number of ways to deal with this problem. One option is to use the delta comparison that's already been mentioned. However, if you know that you'll only be dealing with numbers of up to digits after the decimal point, you can instead multiply everything by 100 use integer numbers instead. This is the advised way if you're doing monetary calculations, for example.
In my graphical tools I'll iterate over an integer value and calculate the floats on the fly:
int bg = 5;
double f = 0.0;
for(int i = 0; i <= bg; i += 1) {
f = f + ((2 * i + 1)*0.1);
if(i == bg)
{
System.out.printf ("%.1f" , f);
}
}

Categories