Is there a Java equivalent of the C / C++ function called frexp? If you aren't familiar, frexp is defined by Wikipedia to "break floating-point number down into mantissa and exponent."
I am looking for an implementation with both speed and accuracy but I would rather have the accuracy if I could only choose one.
This is the code sample from the first reference. It should make the frexp contract a little more clear:
/* frexp example */
#include <stdio.h>
#include <math.h>
int main ()
{
double param, result;
int n;
param = 8.0;
result = frexp (param , &n);
printf ("%lf * 2^%d = %f\n", result, n, param);
return 0;
}
/* Will produce: 0.500000 * 2^4 = 8.000000 */
How's this?
public static class FRexpResult
{
public int exponent = 0;
public double mantissa = 0.;
}
public static FRexpResult frexp(double value)
{
final FRexpResult result = new FRexpResult();
long bits = Double.doubleToLongBits(value);
double realMant = 1.;
// Test for NaN, infinity, and zero.
if (Double.isNaN(value) ||
value + value == value ||
Double.isInfinite(value))
{
result.exponent = 0;
result.mantissa = value;
}
else
{
boolean neg = (bits < 0);
int exponent = (int)((bits >> 52) & 0x7ffL);
long mantissa = bits & 0xfffffffffffffL;
if(exponent == 0)
{
exponent++;
}
else
{
mantissa = mantissa | (1L<<52);
}
// bias the exponent - actually biased by 1023.
// we are treating the mantissa as m.0 instead of 0.m
// so subtract another 52.
exponent -= 1075;
realMant = mantissa;
// normalize
while(realMant > 1.0)
{
mantissa >>= 1;
realMant /= 2.;
exponent++;
}
if(neg)
{
realMant = realMant * -1;
}
result.exponent = exponent;
result.mantissa = realMant;
}
return result;
}
This is "inspired" or actually nearly copied identically from an answer to a similar C# question. It works with the bits and then makes the mantissa a number between 1.0 and 0.0.
This does do what you want.
public class Test {
public class FRex {
public FRexPHolder frexp (double value) {
FRexPHolder ret = new FRexPHolder();
ret.exponent = 0;
ret.mantissa = 0;
if (value == 0.0 || value == -0.0) {
return ret;
}
if (Double.isNaN(value)) {
ret.mantissa = Double.NaN;
ret.exponent = -1;
return ret;
}
if (Double.isInfinite(value)) {
ret.mantissa = value;
ret.exponent = -1;
return ret;
}
ret.mantissa = value;
ret.exponent = 0;
int sign = 1;
if (ret.mantissa < 0f) {
sign = -1; // Thx Kevin
ret.mantissa = -(ret.mantissa);
}
while (ret.mantissa < 0.5f) {
ret.mantissa *= 2.0f;
ret.exponent -= 1;
}
while (ret.mantissa >= 1.0f) {
ret.mantissa *= 0.5f;
ret.exponent++;
}
ret.mantissa *= sign;
return ret;
}
}
public class FRexPHolder {
int exponent;
double mantissa;
}
public static void main(String args[]) {
new Test();
}
public Test() {
double value = 8.0;
//double value = 0.0;
//double value = -0.0;
//double value = Double.NaN;
//double value = Double.NEGATIVE_INFINITY;
//double value = Double.POSITIVE_INFINITY;
FRex test = new FRex();
FRexPHolder frexp = test.frexp(value);
System.out.println("Mantissa: " + frexp.mantissa);
System.out.println("Exponent: " + frexp.exponent);
System.out.println("Original value was: " + value);
System.out.println(frexp.mantissa+" * 2^" + frexp.exponent + " = ");
System.out.println(frexp.mantissa*(1<<frexp.exponent));
}
}
See Float.floatToIntBits and Double.doubleToLongBits. You still need a little additional logic to decode IEEE 754 floating points.
If I'm reading this right...
public class Frexp {
public static void main (String[] args)
{
double param, result;
int n;
param = 8.0;
n = Math.getExponent(param);
//result = ??
System.out.printf ("%f * 2^%d = %f\n", result, n, param);
}
}
Unfortunately, there doesn't appear to be a built-in method to get the mantissa without converting it to a BigDecimal first (or just doing the division: result = param / Math.pow(2,n).
Strangely enough, scalb does the exact opposite: take a mantissa and exponent and generate a new float from it.
I'm not familiar with the frexp function, but I think you need to look at the BigDecimal' scaled and unscaled values. 'unscaled' is the precision mantissa, scale is the exponent. In psuedocode: value = unscaledValue 10^(-scale)
Nope there is no current implementation in core Java or in the Commons Lang(most likely other place to find it) that has the exact same functionality and ease of frexp; that I know of. If it does exist it's probably in a not widely used toolkit.
Related
I'm trying to do the Taylor expansion of the sine of x, but given x greater than 150 degrees, the function diverges.
Here´s my code:
package TaylorJ;
import java.math.*;
public class SeriesSin {
Here I bound the Dominion to be [0, 2pi].
public static double Dominion(double x) {
double dpi = 2*Math.PI;
double dmx = 0;
if((x>=0 && x<=dpi)) {
dmx = x;
}
else if(x<0) {
dmx = dpi+(x%dpi);
}
else {
dmx = x%dpi;
}
return dmx;
}
Here, I defined a factorial function
public static int Factorial(int n) {
n = Math.abs(n);
int a = 1;
int b = 1;
if(n==0 || n == 1) {
return 1;
}
else {
for(int i=n; i>1;i--) {
b *=i;
}
return b;
}
}
Here's the Taylor (Maclaurin) series expansion for sin(x)
public static double Sin(double x) {
if(x%Math.PI == 0) {
x = Dominion(x);
}
else {
x = Dominion(Math.abs(Math.toRadians(x)));
}
int j = 0;
double nmu = 0;
double d1 = 10;
double d2 = 0;
do {
d1 = nmu;
nmu = nmu+ Math.pow(-1,j)*((Math.pow(x, ((2*j)+1)))/(Factorial((2*j)+1)));
d2 = nmu;
j = j+1;
}while((Math.abs(Math.abs(d2)-Math.abs(d1))>0.0001));
return nmu;
}
}
The thing is that it has to be defined for x in [0, 2pi], so I don't know what to do.
Thanks
The error is most likely a ripple effect of numerical over/undeflows. Note that the values of the factorial function, that you use as intermediate results in your computation, grow rather quickly. Using standard floating point number representations you will lose accuracy in computations rather quickly.
However, each of your summation terms can be computed by multiplying the previous term in the series with a suitable factor. This way you avoid overly large or small interim results.
Any text on numerical analysis should provide a much more detailed and stringent discussion.
In your code, replace the loop with the following code:
double asummandj = x;
do {
d1 = nmu;
nmu = nmu + Math.pow(-1,j) * asummandj;
d2 = nmu;
j = j+1;
asummandj = asummandj * (x / (2*j)) * (x / (2*j+1));
} while(Math.abs( d2 - d1 ) > 0.0001);
I got curious about a rounding algorithm, because in CS we had to emulate an HP35 without using the Math library. We didn't include a rounding algorithm in our final build, but I wanted to do it anyway.
public class Round {
public static void main(String[] args) {
/*
* Rounds by using modulus subtraction
*/
double a = 1.123599;
// Should you port this to another method, you can take this as a parameter
int b = 5;
double accuracy = Math.pow(10, -b);
double remainder = a % accuracy;
if (remainder >= 5 * accuracy / 10) // Divide by ten is important because remainder is smaller than accuracy
a += accuracy;
a -= remainder;
/*
* Removes round off error done by modulus
*/
String string = Double.toString(a);
int index = string.indexOf('.') + b;
string = string.substring(0, index);
a = Double.parseDouble(string);
System.out.println(a);
}
}
Is this a good algorithm, or are there any better ones? I don't care about the ones defined in the Java API, I just wanted to know how it was done.
[EDIT]
Here's the code I came up with after looking over EJP's answer
public class Round {
public static void main(String[] args) {
double a = -1.1234599;
int b = 5;
boolean negative = a < 0;
if (negative) a = -a;
String string = Double.toString(a);
char array[] = string.toCharArray();
int index = string.indexOf('.') + b;
int i = index;
int value;
if (Character.getNumericValue(array[index +1]) >= 5) {
for (; i > 0; i--) {
value = Character.getNumericValue(array[i]);
if (value != -1) {
++value;
String temp = Integer.toString(value)
array[i] = temp.charAt(temp.length()-1);
if (value <= 9) break;
}
}
}
string = "";
for (int j=0; j < index + 1 ; j++) {
string += array[j];
}
a = Double.parseDouble(string);
if (negative) a =-a;
System.out.println(a);
}
}
Floating-point numbers don't have decimal places. They have binary places, and the two are not commensurable. Any attempt to modify a floating-point variable to have a specific number of decimal places is doomed to failure.
You have to do the rounding to a specified number of decimal places after conversion to a decimal radix.
There are a different ways to round numbers. The RoundingMode documentation for Java (introduced in 1.5) should give you a brief introduction to the different methods people use.
I know you said you don't have access to the Math functions, but the simplest rounding you can do is:
public static double round(double d)
{
return Math.floor(d + 0.5);
}
If you don't want to use any Math functions, you could try something like this:
public static double round(double d)
{
return (long)(d + 0.5);
}
Those two probably behave differently in some situations (negative numbers?).
I was asked this on an interview a while back and couldn't figure it out. I wasn't allowed to cast the entire thing at once so my next idea was to just run through the string converting until the point but the guy interviewing me told me he wanted to do something like this:
1 = 1
12 = 1 * 10 + 2
123 = 12 * 10 + 3
1234 = 123 * 10 + 4
The input is convert "1234.567" to a float ie. 1234.567
I honestly have no idea how he meant to do it and I haven't been able to produce good enough code to show you guys all I had was the for cycling to parse each character:
for(int i = 0; i < str.length(); i++){
if(!str.charAt(i).equals(".")){
fp = Float.parseFloat("" + str.charAt(i));
Something like this (note: no error checking):
public float parseFloatFromString(final String input)
{
boolean seenDot = false;
float divisor = 1.0f;
char c;
float ret = 0.0f;
for (int i = 0; i < input.length(); i++) {
c = input.charAt(i);
if (c == '.') {
seenDot = true;
continue;
}
ret *= 10.0f;
ret += (float) (c - '0');
if (seenDot)
divisor *= 10.0f;
}
ret /= divisor;
return ret;
}
Of course, you are limited by what a float can represent as decimal numbers -- ultimately, not much. Especially in this case where you multiply/add all the time, and let's not talk about the final division (if the divisor is not 1).
Interesting note about the above: in fact, it appears that this may yield different results on different platforms... Modern JVMs on modern platforms may use an internal, higher precision intermediate representation for floating points. If you want the same result everywhere, you have to add the modifier strictfp to the method declaration:
public strictfp float parseFloatFromString(final String input)
More details here.
This isn't especially elegant, but does work.
String s = "1234.567";
Float fp = 0f;
Float fpd = 0f;
int i =0;
while(s.charAt(i) != '.') {
fp = (fp * 10) + Float.parseFloat(s.substring(i, (i+1)));
i++;
}
int d = s.indexOf('.');
for(i = s.length()- 1; i > d; i--) {
fpd = (fpd * 0.1f) + (Float.parseFloat(s.substring(i, (i+1))) * 0.1f);
}
fp += fpd;
System.out.println(fp);
I can't understand what's your meaning? Did you meaning that convert the integer like '123456' to '12345 * 10 + 6', if you want to do this, just use the 'substring' method to do this.
You would want to trim the source string and then create the number a digit at a time, while counting how many digits occur after an optional decimal point (so you can scale the resulting number).
public class MakeFloat {
private static MakeFloat me;
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
me = new MakeFloat();
String source = " 1234.567";
float result = me.start(source);
System.out.println(" " + source + "=" + result);
}
private float start(String string) {
final String digits = "0123456789";
final float[] values = {0,1,2,3,4,5,6,7,8,9};
float ten = 10;
float result = 0;
float scale = 1;
boolean isAfterDecimal = false;
String stepThrough = string.trim();
for (int i = 0; i < stepThrough.length(); i++) {
// see if we have a digit or a decimal point
String digit = stepThrough.substring(i, i + 1);
int loc = digits.indexOf(digit);
if (loc > -1) {
result = ten * result + values[loc];
if (isAfterDecimal) {
scale = scale * ten;
}
} else if (".".equals(digit)) {
if (isAfterDecimal) {
// handle error
} else {
isAfterDecimal = true;
}
} else {
// handle bad character
}
}
return result / scale;
}
}
To convert a string to a float, I personally use this:
Float.parseFloat("1234.567");
For what the guy wanted, this would be my way of doing it:
String num = "1234.567";
int dotLocation = num.indexOf(".");
int wholeNum = Integer.parseInt(num.substring(0, dotLocation));
String answer = (wholeNum / 10) + " * 10 + " + (wholeNum % 10);
Locate the position of the "." in the string, then extract the whole number by taking a substring of the original string. This would give us 1234.
We now then need to format it such that we get 1234 = 123 * 10 + 4.
Mathematically, when you divide 1234 by 10, the quotient would be 123 and the remainder would be 4. This would give you the answer the guy wanted.
package com.nanofaroque.float2String;
public class Float2String {
public static void main(String[] args) {
String input="1234.56";
String str=".";
float result=0;
int j=3;//this is used for multiply by 10^j
for(int i=0;i<input.length();i++){
if (input.charAt(i)!=str.charAt(0)){
char m=input.charAt(i);//Convert String to Character
float x=(float) input.charAt(i);//Getting the ASCI value
x=x-48;//Now x converted to the real float value
float y=(float) (x* (Math.pow(10, j)));//Multiplication Operation for conversion
result=result+y;
j=j-1;
}
else{
System.out.println("Welcome to my World");// to make the loop work..You can change it if you want
}
}
System.out.println("Result after the conversion:"+result);
}
}
I have tried to separate 5.6 (for example) by the following method:
private static double[] method(double d)
{
int integerPart = 0;
double fractionPart = 0.0;
integerPart = (int) d;
fractionPart = d - integerPart;
return new double[]{integerPart, fractionPart};
}
But what I got is:
[0] = 5.0
[1] = 0.5999999999999996
Do you have any suggestion about doing this without converting the number to string?
Use BigDecimal to do that same calculation. (using doubles has precision problems because of its representation).
Construct it with new BigDecimal(String.valueOf(yourDouble)) (this is still going through string, but the parts are not separated via string manipulation)
use bd.subtract(new BigDecimal(bd.intValue()) to determine the fraction
Here is another solution based on BigDecimal (that does not go through a String).
private static double[] method(double d) {
BigDecimal bd = new BigDecimal(d);
return new double[] { bd.intValue(),
bd.remainder(BigDecimal.ONE).doubleValue() };
}
As you'll note, you still won't get just 0.6 as output for the fractional part. (You can't even store 0.6 in a double!) This is due to the fact that the mathematical, real number, 5.6 is actually not represented by a double exactly as 5.6 but as 5.599999...
You could also do
private static double[] method(double d) {
BigDecimal bd = BigDecimal.valueOf(d);
return new double[] { bd.intValue(),
bd.remainder(BigDecimal.ONE).doubleValue() };
}
which actually does yield [5.0, 0.6].
The BigDecimal.valueOf is in most JDK's (internally) implemented through a call to Double.toString however. But at least the string-related stuff doesn't clutter your code :-)
Good follow-up question in comment:
If it is represented as 5.599999999..., then why Double.toString(5.6) gives exactly "5.6"
The Double.toString method is actually very sophisticated. From the documentation of Double.toString:
[...]
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
[...]
The code for getting the characters "5.6" boils down to FloatingDecimal.getChars:
private int getChars(char[] result) {
assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
int i = 0;
if (isNegative) { result[0] = '-'; i = 1; }
if (isExceptional) {
System.arraycopy(digits, 0, result, i, nDigits);
i += nDigits;
} else {
if (decExponent > 0 && decExponent < 8) {
// print digits.digits.
int charLength = Math.min(nDigits, decExponent);
System.arraycopy(digits, 0, result, i, charLength);
i += charLength;
if (charLength < decExponent) {
charLength = decExponent-charLength;
System.arraycopy(zero, 0, result, i, charLength);
i += charLength;
result[i++] = '.';
result[i++] = '0';
} else {
result[i++] = '.';
if (charLength < nDigits) {
int t = nDigits - charLength;
System.arraycopy(digits, charLength, result, i, t);
i += t;
} else {
result[i++] = '0';
}
}
} else if (decExponent <=0 && decExponent > -3) {
result[i++] = '0';
result[i++] = '.';
if (decExponent != 0) {
System.arraycopy(zero, 0, result, i, -decExponent);
i -= decExponent;
}
System.arraycopy(digits, 0, result, i, nDigits);
i += nDigits;
} else {
result[i++] = digits[0];
result[i++] = '.';
if (nDigits > 1) {
System.arraycopy(digits, 1, result, i, nDigits-1);
i += nDigits-1;
} else {
result[i++] = '0';
}
result[i++] = 'E';
int e;
if (decExponent <= 0) {
result[i++] = '-';
e = -decExponent+1;
} else {
e = decExponent-1;
}
// decExponent has 1, 2, or 3, digits
if (e <= 9) {
result[i++] = (char)(e+'0');
} else if (e <= 99) {
result[i++] = (char)(e/10 +'0');
result[i++] = (char)(e%10 + '0');
} else {
result[i++] = (char)(e/100+'0');
e %= 100;
result[i++] = (char)(e/10+'0');
result[i++] = (char)(e%10 + '0');
}
}
}
return i;
}
To see what is going on, take a look at the binary representations of the numbers:
double d = 5.6;
System.err.printf("%016x%n", Double.doubleToLongBits(d));
double[] parts = method(d);
System.err.printf("%016x %016x%n",
Double.doubleToLongBits(parts[0]),
Double.doubleToLongBits(parts[1]));
output:
4016666666666666
4014000000000000 3fe3333333333330
5.6 is 1.4 * 22, but 0.6 is 1.2 * 2-1. Because it has a lower exponent, normalization causes the mantissa to be shifted three bits to the left. The fact that the recurring terms (..66666..) were originally an approximation of the fraction 7/5 has been forgotten, and the missing bits are replaced with zeros.
Given the original double value as input to your method, there is no way to avoid this. To preserve the exact value you would need to use a format that represents the desired value exactly, e.g. Fraction from Apache commons-math. (For this specific example with d=5.6 a BigDecimal would also be able to represent it exactly, but there are other numbers it cannot represent exactly, e.g. 4/3)
poor-man solution (using String)
static double[] sp(double d) {
String str = String.format(Locale.US, "%f", d);
int i = str.indexOf('.');
return new double[] {
Double.parseDouble(str.substring(0, i)),
Double.parseDouble(str.substring(i))
};
}
(Locale so we really get a decimal point)
String doubleAsString = Double.toString(123.456);
String beforeDecimal=doubleAsString.substring(0,doubleAsString.indexOf(".")); //123
String afterDecimal=doubleAsString.substring(doubleAsString.indexOf(".")+1); //456
I have a BigInteger value, let's say it is 282 and is inside the variable x. I now want to write a while loop that states:
while b2 isn't a perfect square:
a ← a + 1
b2 ← a*a - N
endwhile
How would I do such a thing using BigInteger?
EDIT: The purpose for this is so I can write this method. As the article states one must check if b2 is not square.
Compute the integer square root, then check that its square is your number. Here is my method of computing the square root using Heron's method:
private static final BigInteger TWO = BigInteger.valueOf(2);
/**
* Computes the integer square root of a number.
*
* #param n The number.
*
* #return The integer square root, i.e. the largest number whose square
* doesn't exceed n.
*/
public static BigInteger sqrt(BigInteger n)
{
if (n.signum() >= 0)
{
final int bitLength = n.bitLength();
BigInteger root = BigInteger.ONE.shiftLeft(bitLength / 2);
while (!isSqrt(n, root))
{
root = root.add(n.divide(root)).divide(TWO);
}
return root;
}
else
{
throw new ArithmeticException("square root of negative number");
}
}
private static boolean isSqrt(BigInteger n, BigInteger root)
{
final BigInteger lowerBound = root.pow(2);
final BigInteger upperBound = root.add(BigInteger.ONE).pow(2);
return lowerBound.compareTo(n) <= 0
&& n.compareTo(upperBound) < 0;
}
I found a sqrt method used here, and simplified the square test.
private static final BigInteger b100 = new BigInteger("100");
private static final boolean[] isSquareResidue;
static{
isSquareResidue = new boolean[100];
for(int i =0;i<100;i++){
isSquareResidue[(i*i)%100]=true;
}
}
public static boolean isSquare(final BigInteger r) {
final int y = (int) r.mod(b100).longValue();
boolean check = false;
if (isSquareResidue[y]) {
final BigInteger temp = sqrt(r);
if (r.compareTo(temp.pow(2)) == 0) {
check = true;
}
}
return check;
}
public static BigInteger sqrt(final BigInteger val) {
final BigInteger two = BigInteger.valueOf(2);
BigInteger a = BigInteger.ONE.shiftLeft(val.bitLength() / 2);
BigInteger b;
do {
b = val.divide(a);
a = (a.add(b)).divide(two);
} while (a.subtract(b).abs().compareTo(two) >= 0);
return a;
}
public static Boolean PerfectSQR(BigInteger A){BigInteger B=A.sqrt(), C=B.multiply(B);return (C.equals(A));}
DON'T use this...
BigInteger n = ...;
double n_as_double = n.doubleValue();
double n_sqrt = Math.sqrt(n_as_double);
BigInteger n_sqrt_as_int = new BigDecimal(n_sqrt).toBigInteger();
if (n_sqrt_as_int.pow(2).equals(n)) {
// number is perfect square
}
As Christian Semrau commented below - this doesn't work. I am sorry for posting incorrect answer.
using System.Numerics; // needed for BigInteger
/* Variables */
BigInteger a, b, b2, n, p, q;
int flag;
/* Assign Data */
n = 10147;
a = iSqrt(n);
/* Algorithm */
do
{ a = a + 1;
b2 = (a * a) – n;
b = iSqrt(b2);
flag = BigInteger.Compare(b * b, b2);
} while(flag != 0);
/* Output Data */
p = a + b;
q = a – b;
/* Method */
private static BigInteger iSqrt(BigInteger num)
{ // Finds the integer square root of a positive number
if (0 == num) { return 0; } // Avoid zero divide
BigInteger n = (num / 2) + 1; // Initial estimate, never low
BigInteger n1 = (n + (num / n)) / 2;
while (n1 < n)
{ n = n1;
n1 = (n + (num / n)) / 2;
}
return n;
} // end iSqrt()
private static boolean isSqrt(BigInteger n, BigInteger root)
{
final BigInteger lowerBound = root.pow(2);
final BigInteger upperBound = root.add(BigInteger.ONE).pow(2);
return lowerBound.compareTo(n) <= 0
&& n.compareTo(upperBound) < 0;
}
I tried the above using JavaScript BigInt:
function isPerfectSqrt(n, root) {
const lowerBound = root**2n;
const upperBound = (root+1n)**2n
return lowerBound <= n && n < upperBound;
}
And found it was only about 60% as fast (in Node V8) as the one-liner:
function isPerfectSqrt(n, root) {
return (n/root === root && n%root === 0n)
}
The number you want to do a perfect square test on is A. B is the integer square root of A and the .sqrt() function returns the integer lower floor of the square root. The Boolean of B*B=A is returned. The Boolean return is "true" if it is a perfect square and "false" if it is not a perfect square.
public static Boolean PerfectSQR(BigInteger A) {
BigInteger B = A.sqrt();
return B.multiply(B).equals(A);
}
An alternative is to use the sqrtAndRemainder() function. If the remainder, B[1], is zero it is a perfect square. The boolean TRUE then is returned as shown below.
public static Boolean PerfectSQR(BigInteger A) {
BigInteger [] B=A.sqrtAndRemainder();
return B[1].equals(BigInteger.ZERO);
}