Manually convert float point number into binary format - java

Hi I have following float point value in base 10: 0.625. I need to convert this value in base 10 to binary format which is: 0.101.
Algorithm I found is below. It works, but I am not understanding why this works. Could someone please explain to be why the code below works? I am aware that numbers after the decimal point is computed in the manner such that 1/2^n where n is count from the decimal point. Thanks.
To clarify, I need to know the reasoning behind the mathematical formula. Not stepping through the code.
private static String floatToBinaryString( double n ) {
String val = "0.";
while ( n > 0 ) {
double r = n * 2;
if( r >= 1 ) {
val += "1";
n = r - 1;
}else{
val += "0";
n = r;
}
}
return val;
}

You multiply the fraction by 2 and use the ones place digit as the binary values until the fraction is equal to zero. Example below.
This is the standard formula for conversion using the 0.625 you have:
1) Multiply fraction by 2 => 0.625 * 2 = 1.25
The digit to the left of the decimal point is the first binary value, 0.1 so far
2) Ignore the ones-place digit and you have 0.25 which is still larger than zero.
Multiply the fraction by 2 => 0.25 * 2 = 0.50
The digit to the left of the decimal point is the next binary value, 0.10 so far
3) Ignore the ones-place digit and you have 0.50 which is less than zero.
Multiply the fraction by 2 => 0.5 * 2 = 1.00
The digit to the left of the decimal point is the next binary value, 0.101 so far
4) Ignore the ones-place digit and you have 0.00 which is equal to zero.
Conversion complete!
private static String floatToBinaryString( double n ) {
String val = "0."; // Setting up string for result
while ( n > 0 ) { // While the fraction is greater than zero (not equal or less than zero)
double r = n * 2; // Multiply current fraction (n) by 2
if( r >= 1 ) { // If the ones-place digit >= 1
val += "1"; // Concat a "1" to the end of the result string (val)
n = r - 1; // Remove the 1 from the current fraction (n)
}else{ // If the ones-place digit == 0
val += "0"; // Concat a "0" to the end of the result string (val)
n = r; // Set the current fraction (n) to the new fraction
}
}
return val; // return the string result with all appended binary values
}

Related

LeetCode Divide Two Integers - Repeated Exponential Searches solution with negative numbers

I am having hard time understanding below solution in leetcode. Why int powerOfTwo = -1 is initialized with -1 as we have already handled divide(INT_MIN, -1) case
:
Adding problem statement -
Given two integers dividend and divisor, divide two integers without using multiplication, division, and mod operator.
Return the quotient after dividing dividend by divisor.
The integer division should truncate toward zero, which means losing its fractional part. For example, truncate(8.345) = 8 and truncate(-2.7335) = -2.
Note:
Assume we are dealing with an environment that could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. For this problem, assume that your function returns 2^31 − 1 when the division result overflows.
Example 1:
Input: dividend = 10, divisor = 3
Output: 3
Explanation: 10/3 = truncate(3.33333..) = 3.
https://leetcode.com/problems/divide-two-integers/solution/
private static int HALF_INT_MIN = -1073741824;
public int divide(int dividend, int divisor) {
// Special case: overflow.
if (dividend == Integer.MIN_VALUE && divisor == -1) {
return Integer.MAX_VALUE;
}
/* We need to convert both numbers to negatives.
* Also, we count the number of negatives signs. */
int negatives = 2;
if (dividend > 0) {
negatives--;
dividend = -dividend;
}
if (divisor > 0) {
negatives--;
divisor = -divisor;
}
int quotient = 0;
/* Once the divisor is bigger than the current dividend,
* we can't fit any more copies of the divisor into it. */
while (divisor >= dividend) {
/* We know it'll fit at least once as divivend >= divisor.
* Note: We use a negative powerOfTwo as it's possible we might have
* the case divide(INT_MIN, -1). */
int powerOfTwo = -1;
int value = divisor;
/* Check if double the current value is too big. If not, continue doubling.
* If it is too big, stop doubling and continue with the next step */
while (value >= HALF_INT_MIN && value + value >= dividend) {
value += value;
powerOfTwo += powerOfTwo;
}
// We have been able to subtract divisor another powerOfTwo times.
quotient += powerOfTwo;
// Remove value so far so that we can continue the process with remainder.
dividend -= value;
}
/* If there was originally one negative sign, then
* the quotient remains negative. Otherwise, switch
* it to positive. */
if (negatives != 1) {
return -quotient;
}
return quotient;
}

Pretty number formatting algorithm

Algorithm to convert an integer representing a number of bytes into an pretty format.
3 digits max (not counting decimal) - for eg like linux command line.
no leading or trailing zeroes
1K is 1000 bytes
Examples:
Correct
123B -> 123B
12300B -> 12.3K
1910000B -> 1.91M
1000000000B -> 1G
83123 = 83.1K (not 83K)
Incorrect
012K (should be 12K)
8.20M (should be 8.2M)
I would like to know what did I do wrong or is there an easy better way to solve this problem or if there are any bugs in my code.
Below is my solution (it works but I was not selected so I have not idea of what I did wrong) -
/*
* #Description - Function takes integer as input and returns the number in
* pretty format(Gigabyte, Megabytes, KiloBytes, Bytes) with maximum of 3
* digits
* #param integer to convert to pretty format
* #Assumptions - As mentioned in the problem set, 1000bytes = 1KB
* Value is rounded to the nearest valid value
* In java leading 0 in number is considered Octal, this function does not
* take care of octal to decimal conversion
* As 1G = 1,000,000,000B the loop will run maximum 3 times in worst case
* Its requires constant space O(1) to store the result
*/
static String fpretty(int num) {
int count = 0;
double div_result = (double) num;
String display = "";
/*
* Every time we divide by 1000 count is incremented from B->K->M->G
* Here two decimal places are preserved for cases like 1.05, 1.11
* The output result of this loop will have 1,2 or 3 digits with max
* two decimal places
*/
while(div_result > 999.5) {
div_result = div_result / 1000;
div_result = Math.round(div_result * 100.0) / 100.0;
count++;
}
// Get suffix B, K, M or G
String measure = getUnit(count);
// If decimal places is all zeros OR result has 3 digits
if(div_result % 1 == 0 || div_result >= 100)
display = (int)div_result + measure;
// If result has 2 digits
else if (div_result >= 10) {
// Then fetch 1 decimal place as we have 2 digits
div_result = (Math.round(div_result * 10.0) / 10.0);
// If after rounding decimal places are .0 then truncate zeros
// eg. 99.97 rounded to -> 100.0 -> 100
if(div_result % 1 == 0)
display = (int)div_result + measure;
else
display = div_result + measure;
}
else
display = div_result + measure;
return display;
}
This can be done with much less effort using the DecimalFormat class. Let it do the rounding for you, which can be described in a pattern and choose the way of rounding by RoundingMode. It also takes care of the trailing zeros, which will be simply ignored.
public String pretty(int num) {
DecimalFormat f = new DecimalFormat("###.##");
f.setRoundingMode(RoundingMode.HALF_UP);
double prettyd = num;
int count = 0;
while (prettyd >= 1000.0) {
prettyd /= 1000.0;
count++;
}
return f.format(prettyd) + getUnit(count);
}

Java binary method for GCD infinate loop

I'm using the Binary Method to calculate the GCD of two fractions, the method works perfectly fine, except for when I subtract certain numbers from each other.
I'm assuming it's because, for instance, when I subtract 2/15 from 1/6, the GCD has a repeating number or something like that, though I could be wrong.
//The following lines calculate the GCD using the binary method
if (holderNum == 0)
{
gcd = holderDem;
}
else if (holderDem == 0)
{
gcd = holderNum;
}
else if ( holderNum == holderDem)
{
gcd = holderNum;
}
// Make "a" and "b" odd, keeping track of common power of 2.
final int aTwos = Integer.numberOfTrailingZeros(holderNum);
holderNum >>= aTwos;
final int bTwos = Integer.numberOfTrailingZeros(holderDem);
holderDem >>= bTwos;
final int shift = Math.min(aTwos, bTwos);
// "a" and "b" are positive.
// If a > b then "gdc(a, b)" is equal to "gcd(a - b, b)".
// If a < b then "gcd(a, b)" is equal to "gcd(b - a, a)".
// Hence, in the successive iterations:
// "a" becomes the absolute difference of the current values,
// "b" becomes the minimum of the current values.
if (holderNum != gcd)
{
while (holderNum != holderDem)
{
//debuging
String debugv3 = "Beginning GCD binary method";
System.out.println(debugv3);
//debugging
final int delta = holderNum - holderDem;
holderNum = Math.min(holderNum, holderDem);
holderDem = Math.abs(delta);
// Remove any power of 2 in "a" ("b" is guaranteed to be odd).
holderNum >>= Integer.numberOfTrailingZeros(holderNum);
gcd = holderDem;
}
}
// Recover the common power of 2.
gcd <<= shift;
That is the code that I'm using to complete this operation, the debugging message prints out forever.
Is there a way to cheat out of this when it gets stuck, or maybe set up an exception?
The problem is with negative values — when one of them is negative, holderNum will always take on the negative value (being the min); holderDem will become postive, so delta equal to a negative less a positive equals a lesser negative. Then holderDem = abs(delta) is a greater positive and keeps increasing. You should take the absolute value of both of them before entering the loop.
E.g.:
holderNum = -1 and holderDem = 6
Iteration 1:
delta = holderNum - holderDem = -1 - 6 = -7
holderNum = Math.min(holderNum, holderDem) = Math.min(-1, 6) = -1
holderDem = Math.abs(delta) = Math.abs(-7) = 7
Iteration 2:
delta = holderNum - holderDem = -1 - 7 = -8
holderNum = Math.min(holderNum, holderDem) = Math.min(-1, 7) = -1
holderDem = Math.abs(delta) = Math.abs(-7) = 8
etc., etc., etc.

How to generate random numbers which will provide proper results on division

How to generate random numbers which will provide proper results on division (i.e the results should round to exactly 1 or 2 places after the decimal point).
(e.g a whole number by a decimal number providing decimal results - I have given a set of sample inputs below)
2827 by 2.5 = 1130.8
1747 by 0.8 = 2183.75
425 by 0.4 = 1062.5
935 by 0.8 = 1168.75
res = input * random.nextInt (100) / 100.0;
Explanation:
You take a whole number n, and multiply it with something. If this something is a number like 34.56, we call the part before the decimal digit w (whole part) and the part behind .xy.
If you multiply this with n, you end with (n*w)+(n*(x/10))+n*(y/100). There will never be an fractional part 3 ciphers behind the dot - do you agree?
We can combine x and y to a single part, and say (n*w) + (n*(xy/100)), and xy is just the name for something from 0 to 100.
Since the part before the decimal dot can be arbitrary large, you can calculate it seperately, if you need something else than 0. But you have to define a range somehow. If you take an random Integer R for that part:
res = input * R * random.nextInt (100) / 100.0;
Do you need the divisor explicityl?
div = 100.0 / (R * random.nextInt (100));
Scala is always handy, when testing code fragmenst:
val r = util.Random
r: util.Random.type = scala.util.Random$#ce2f12
scala> def res (input: Int) = input * r.nextInt (100) / 100.0;
res: (input: Int)Double
scala> (1 to 20).map (res)
res338: scala.collection.immutable.IndexedSeq[Double] =
Vector(0.48, 1.58, 0.48, 2.8, 0.15, 1.98, 5.67, 3.36, 6.93, 6.0, 9.02, 0.48, 7.41, 6.44, 9.6, 1.92, 16.66, 5.94, 7.98, 18.4)
It is worth noting that all integers can be divided by 0.4, 0.8 or 2.5 and be represented to two decimal places. This is because it is the same as multiplying by 2.5, 1.25, and 0.4
However, if you have a divisor for which this is not true, you can do this in a loop.
double divisor = 2.4;
double factor = 100/divisor;
Random rand = new Random();
int maxValue = 1000;
double ERROR = 1e-14*maxValue;
for(int i=0;i<100;i++) {
long randNum;
do {
randNum = rand.nextInt(maxValue+1);
if (Math.abs(randNum * factor - (long) (randNum * factor)) > ERROR)
System.out.println("reject "+randNum + " => "+randNum/divisor);
} while(Math.abs(randNum * factor - (long) (randNum * factor)) > ERROR);
System.out.println(randNum + " => "+randNum/divisor);
prints
729 => 303.75
285 => 118.75
84 => 35.0
123 => 51.25
999 => 416.25
75 => 31.25
reject 727 => 302.9166666666667
reject 842 => 350.83333333333337
504 => 210.0
reject 368 => 153.33333333333334
441 => 183.75
579 => 241.25
165 => 68.75
This will generate random numbers until you have a number which is a multiple of 0.01.
If you want the result to 'round' to 2 decimal places (it's not really rounding, it's just a finite decimal representation with two decimal points), then just generate the divisor, and have the dividend always be 100, e.g.:
106250 / 100 = 1062.5
116875 / 100 = 1168.75
If you want more interesting dividends then divide the divisor and dividend. e.g. the first one could be any one of:
(/1): 106250 / 100 = 1062.5
(/2): 53125 / 50 = 1062.5
(/10): 10625 / 10 = 1062.5
(/4): 26562.5 / 25 = 1062.5
(/125): 850 / 0.8 = 1062.5
For me the dividend and divisor are both random numbers. I have to produce an answer which doesn't require rounding decimals beyond 2 decimal places.
If that is the case, the answer might be "there is no such number". Here's a little Java program I wrote to test this hypothesis:
import java.text.DecimalFormat;
public class Test {
public static void main(String[] args) {
double num = Math.PI;
DecimalFormat format = new DecimalFormat(
"####################################0." +
"00##############################");
while (true) {
for (int i = 1; i < Integer.MAX_VALUE; i++) {
double tmp = (i / num) * 100;
if (tmp == (long) tmp) {
System.err.println("Solution - " + i + " - " +
format.format(tmp) + " - " + format.format(num));
break;
}
}
pi = Math.nextAfter(num, 1);
}
System.err.println("No solution for " + format.format(num));
}
}
I ran this for 10 minutes (starting at PI), and didn't find any values of num that had no solution i. But I did observe that solutions can be very sparse. For instance:
Gotcha! - 179453441 - 5712180438.00 - 3.1415926535897714
It took 179 million attempts to find the solution for that divisor.

Generate a random binary number with a variable proportion of '1' bits

I need a function to generate random integers. (assume Java long type for now, but this will be extended to BigInteger or BitSet later.)
The tricky part is there is a parameter P that specifies the (independent) probability of any bit in the result being 1.
If P = 0.5 then we can just use the standard random number generator. Some other values of P are also easy to implement. Here's an incomplete example:
Random random = new Random();
// ...
long nextLong(float p) {
if (p == 0.0f) return 0L;
else if (p == 1.0f) return -1L;
else if (p == 0.5f) return random.nextLong();
else if (p == 0.25f) return nextLong(0.5f) & nextLong(0.5f);
else if (p == 0.75f) return nextLong(0.5f) | nextLong(0.5f);
else if (p == 0.375f) return nextLong(0.5f) & nextLong(0.75f); // etc
else {
// What goes here??
String message = String.format("P=%f not implemented yet!", p);
throw new IllegalArgumentException(message);
}
}
Is there a way to generalise this for any value of P between 0.0 and 1.0?
First a little ugly math that you're already using in your code.
Define x and y are bits with probability of being 1 of X = p(x=1), Y = p(y=1) respectively.
Then we have that
p( x & y = 1) = X Y
p( x | y = 1) = 1 - (1-X) (1-Y)
p( x ^ y = 1) = X (1 - Y) + Y (1 - X)
Now if we let Y = 1/2 we get
P( x & y ) = X/2
P( x | y ) = (X+1)/2
Now set the RHS to the probability we want and we have two cases that we can solve for X
X = 2 p // if we use &
X = 2 p - 1 // if we use |
Next we assume we can use this again to obtain X in terms of another variable Z...
And then we keep iterating until we've done "enough".
Thats a bit unclear but consider p = 0.375
0.375 * 2 = 0.75 < 1.0 so our first operation is &
0.75 * 2 = 1.5 > 1.0 so our second operation is |
0.5 is something we know so we stop.
Thus we can get a variable with p=0.375 by X1 & (X2 | X3 )
The problem is that for most variables this will not terminate. e.g.
0.333 *2 = 0.666 < 1.0 so our first operation is &
0.666 *2 = 1.333 > 1.0 so our second operation is |
0.333 *2 = 0.666 < 1.0 so our third operation is &
etc...
so p=0.333 can be generated by
X1 & ( X2 | (X3 & (X4 | ( ... ) ) ) )
Now I suspect that taking enough terms in the series will give you enough accuracy, and this can be written as a recursive function. However there might be a better way that that too... I think the order of the operations is related to the binary representation of p, I'm just not sure exactly how... and dont have time to think about it deeper.
Anyway heres some untested C++ code that does this. You should be able to javaify it easily.
uint bitsWithProbability( float p )
{
return bitsWithProbabilityHelper( p, 0.001, 0, 10 );
}
uint bitsWithProbabilityHelper( float p, float tol, int cur_depth, int max_depth )
{
uint X = randbits();
if( cur_depth >= max_depth) return X;
if( p<0.5-tol)
{
return X & bitsWithProbabilityHelper( 2*p, 0.001, cur_depth+1, max_depth );
}
if(p>0.5+tol)
{
return X | bitsWithProbabilityHelper( 2*p-1, 0.001, cur_depth+1, max_depth );
}
return X;
}
Distribute proportional number of bits throughuot the number.
Pseudocode:
long generateNumber( double probability ){
int bitCount = 64 * probability;
byte[] data = new byte[64]; // 0-filled
long indexes = getRandomLong();
for 0 to bitCount-1 {
do {
// distribute this bit to some postition with 0.
int index = indexes & 64;
indexes >> 6;
if( indexes == 0 ) indexes = getRandomLong();
} while ( data[index] == 0 );
data[index] = 1;
}
return bytesToLong( data );
}
I hope you get what I mean. Perhaps the byte[] could be replaced with a long and bit operations to make it faster.
Here's how I solved it in the end.
Generate an integer N between 0..16, following the binomial distribution. This gives the number of '1' bits in the 16-bit partial result.
Randomly generate an index into a lookup table that contains 16-bit integers containing the desired number of '1' bits.
Repeat 4 times to get four 16-bit integers.
Splice these four 16-bit integers together to get a 64-bit integer.
This was partly inspired by Ondra Žižka's answer.
The benefit is that it reduces the number of calls to Random.nextLong() to 8 calls per 64 bits of output.
For comparison, rolling for each individual bit would require 64 calls. Bitwise AND/OR uses between 2 and 32 calls depending on the value of P
Of course calculating binomial probabilities is just as expensive, so those go in another lookup table.
It's a lot of code, but it's paying off in terms of performance.
Update - merged this with the bitwise AND/OR solution. It now uses that method if it guesses it will be more efficient (in terms of calls to Random.next().)
Use a random generator that generates a uniform float number r between 0 and 1. If r>p then set the bit to 0, otherwise set it to 1
If you're looking to apply some distribution where with probability P you get a 1 and with probability 1-P you get a 0 at any particular bit your best bet is simply to generate each bit independently with probability P of being a 1 (that sounds like a recursive definition, I know).
Here's a solution, I'll walk through it below:
public class MyRandomBitGenerator
{
Random pgen = new Random();
// assumed p is well conditioned (0 < p < 1)
public boolean nextBitIsOne(double p){
return pgen.nextDouble() < p ? true : false;
}
// assumed p is well conditioned (0 < p < 1)
public long nextLong(double p){
long nxt = 0;
for(int i = 0; i < 64; i++){
if(nextBitIsOne(p)){
nxt += 1 << i;
}
}
return nxt;
}
}
Basically, we first determine how to generate a value of 1 with probability P: pgen.nextDouble() generates a number between 0 and 1 with uniform probability, by asking if it's less than p we're sampling this distribution such that we expect to see p 1s as we call this function infinitely.
Here's another variant of Michael Anderson's answer
To avoid recursion, we process the bits of P iteratively from right-to-left instead of recursively from left-to-right. This would be tricky in floating-point representation so we extract the exponent/mantissa fields from the binary representation instead.
class BitsWithProbabilityHelper {
public BitsWithProbabilityHelper(float prob, Random rnd) {
if (Float.isNaN(prob)) throw new IllegalArgumentException();
this.rnd = rnd;
if (prob <= 0f) {
zero = true;
return;
}
// Decode IEEE float
int probBits = Float.floatToIntBits(prob);
mantissa = probBits & 0x7FFFFF;
exponent = probBits >>> 23;
// Restore the implicit leading 1 (except for denormals)
if (exponent > 0) mantissa |= 0x800000;
exponent -= 150;
// Force mantissa to be odd
int ntz = Integer.numberOfTrailingZeros(mantissa);
mantissa >>= ntz;
exponent += ntz;
}
/** Determine how many random words we need from the system RNG to
* generate one output word with probability P.
**/
public int iterationCount() {
return - exponent;
}
/** Generate a random number with the desired probability */
public long nextLong() {
if (zero) return 0L;
long acc = -1L;
int shiftReg = mantissa - 1;
for (int bit = exponent; bit < 0; ++ bit) {
if ((shiftReg & 1) == 0) {
acc &= rnd.nextLong();
} else {
acc |= rnd.nextLong();
}
shiftReg >>= 1;
}
return acc;
}
/** Value of <code>prob</code>, represented as m * 2**e where m is always odd. */
private int exponent;
private int mantissa;
/** Random data source */
private final Random rnd;
/** Zero flag (special case) */
private boolean zero;
}
Suppose the size of bit array is L. If L=1, the chance that the 1st bit is 1 will be P, and that being 0 will be 1-P. For L=2, the probability of getting a 00 is (1-P)2, a 01 or 10 is P(1-P) each and 11 is P2. Extending this logic, we can first determine the first bit by comparing a random number with P, then scale the random number such that we can again get anything between 0 to 1. A sample javascript code:
function getRandomBitArray(maxBits,probabilityOf1) {
var randomSeed = Math.random();
bitArray = new Array();
for(var currentBit=0;currentBit<maxBits;currentBit++){
if(randomSeed<probabilityOf1){
//fill 0 at current bit
bitArray.push(0);
//scale the sample space of the random no from [0,1)
//to [0.probabilityOf1)
randomSeed=randomSeed/probabilityOf1;
}
else{
//fill 1 at current bit
bitArray.push(1);
//scale the sample space to [probabilityOf1,1)
randomSeed = (randomSeed-probabilityOf1)/(1-probabilityOf1);
}
}
}
EDIT:
This code does generate completely random bits. I will try to explain the algorithm better.
Each bit string has a certain probability of occurring. Suppose a string has a probability of occurrence p; we want to choose that string if our random number falls is some interval of length p. The starting point of the interval must be fixed, but its value will not make much difference. Suppose we have chosen upto k bits correctly. Then, for the next bit, we divide the interval corresponding to this k-length bit-string into two parts of sizes in the ratio P:1-P (here P is the probability of getting a 1). We say that the next bit will be 1 if the random number is in the first part, 0 if it is in the second part. This ensure that the probabilities of strings of length k+1 also remain correct.
Java code:
public ArrayList<Boolean> getRandomBitArray(int maxBits, double probabilityOf1) {
double randomSeed = Math.random();
ArrayList<Boolean> bitArray = new ArrayList<Boolean>();
for(int currentBit=0;currentBit<maxBits;currentBit++){
if(randomSeed<probabilityOf1){
//fill 0 at current bit
bitArray.add(false);
//scale the sample space of the random no from [0,1)
//to [0.probabilityOf1)
randomSeed=randomSeed/probabilityOf1;
}
else{
//fill 1 at current bit
bitArray.add(true);
//scale the sample space to [probabilityOf1,1)
randomSeed = (randomSeed-probabilityOf1)/(1-probabilityOf1);
}
}
return bitArray;
}

Categories