I am trying to use the non-restoring algorithm for computing the square root of a floating point number.
For instance, say x = 1001, the square root is 31.6386
I want to calculate this square root using the non-restoring method.
I tried following the method in the paper:
Implementation of Single Precision Floating Point Square Root on FPGAs
but it appears my result is slightly off by 1 bit. I'm not able to figure out why though.
For instance, the program I wrote below will produce the following results:
correct_result =
41FD1BD2
myresult =
41FD1BD1
error =
1.192093e-007
C++ version of the code :
#include <iostream>
#include <cmath>
using namespace std;
union newfloat{
float f;
int i;
};
int main () {
// Input number
newfloat x;
cout << "Enter Number: ";
cin >> x.f;
// Pull out exponent and mantissa
int exponent = (x.i >> 23) & 0xFF;
int mantissa = (x.i & 0x7FFFFF) | ((exponent && exponent) << 23);
// Calculate new exponent
int new_exponent = (exponent >> 1) + 63 + (exponent & 1);
// Shift right (paper says shift left but shift left doesn't work?)
if (exponent & 1) {
mantissa = mantissa >> 1;
cout << " Shifted right " << endl;
}
// Create an array with the bits of the mantissa
unsigned int D [48];
for (int i = 47; i >= 0; i--) {
if (i >= 24) {
D[i] = (mantissa >> (i-24)) & 1;
} else {
D[i] = 0;
}
}
// == Perform square root ==
// Set q24 = 0, r24 = 0 and then iterate from k = 23 to 0
int q[25] = {0}; // 25 element array, indexing ends at 24
int r[25] = {0};
for (int k = 23; k >= 0; k--) {
if (r[k+1] >= 0) {
r[k] = ((r[k+1] << 2) | (D[2*k+1] << 1) | D[2*k] ) - (q[k+1] << 2 | 1 );
} else {
r[k] = ((r[k+1] << 2) | (D[2*k+1] << 1) | D[2*k] ) + (q[k+1] << 2 | 0x3 );
}
if (r[k] >= 0) {
q[k] = (q[k+1] << 1) | 1;
} else {
q[k] = q[k+1] << 1;
}
if (k == 0) {
if (r[0] < 0) {
r[0] = r[0] + (q[0] << 1) | 1;
}
}
}
// Create quotient from LSBs of q[]
int Q = 0;
for (int i = 0; i <= 23; i++) {
Q = Q | ((q[i] & 1) << i);
}
// Option 1 Rounding
//if (r[0] > 0) // Works for 10, 1001, 1021, but not 1012
// Q = Q + 1;
// Option 2 Rounding (No rounding)
// Works for 1012, Doesn't work for 10, 1001, 1021
// Option 3 Rounding (Calculate the next 3 Quotient bits to get a guard round and sticky bit)
// Calculate correct result:
newfloat correct_result;
correct_result.f = sqrt(x.f);
// Form my result into a single number
newfloat myresult;
myresult.i = (new_exponent << 23) | (Q & 0x7FFFFF);
// Print results
cout << hex << "My result: " << myresult.i << endl;
cout << hex << "Correct: " << correct_result.i << endl;
return 0;
}
First let me highlight the relevant part from the paper:
You need to take another look at how the additions/subtractions are done. You code is performing it in regular double-numbers, but I think the algorithm is designed with integer modular arithmetic in mind.
So if you look at the example listed later in the paper, the computation of 0011 - 0101 wraps around to give 1110.
That could explain why you're getting the wrong results, I think :)
I was looking through the c++ version of your program and reading that document today. It seems to me that the algorithm is intended to provide both a quotient and a remainder. As in the example provided, he uses his algorithm to get the square root of 127, to which it provides a result of 11 + R 6. 112 + 6 = 127.
That was with an integer, but every data type has a limit to its precision. This leads me to believe that your program is executing as expected, its just that you've run out of precision, at least for the way the square root is being calculated, and for the data type being used. I expect you would find your minute "lost" precision in r[0].
I saw from the comments in the code that you intended to, or tried to calculate out extra precision. That seems like a reasonable path to try. Do note that, in addition to the other changes that would be required to do this, you would have to take out (or move) the check k == 0; since it modifies the remainder, which would mess up the loop.
I think the real question is what size precision is acceptable to you. For instance, the c++ sqrt function (and yours) are off by 0.00000002 on sqrt(2). No one seems to mind. Considering the program you wrote is off from the c++ sqrt function by less than that in the instances where it doesn't match. I spent the majority of the day breaking it down, testing the individual parts, and reviewing the subject matter, and couldn't find anything blatantly wrong. It seem close enough for government work to me.
Related
Given the binary representation of an integer as a string s, return the number of steps to reduce it to 1 under the following rules:
If the current number is even, you have to divide it by 2.
If the current number is odd, you have to add 1 to it.
It is guaranteed that you can always reach one for all test cases.
Step 1) 13 is odd, add 1 and obtain 14.
Step 2) 14 is even, divide by 2 and obtain 7.
Step 3) 7 is odd, add 1 and obtain 8.
Step 4) 8 is even, divide by 2 and obtain 4.
Step 5) 4 is even, divide by 2 and obtain 2.
Step 6) 2 is even, divide by 2 and obtain 1.
My input = 1111011110000011100000110001011011110010111001010111110001
Expected output = 85
My output = 81
For the above input, the output is supposed to be 85. But my output shows 81. For other test cases it
seems to be giving the right answer. I have been trying all possible debugs, but I am stuck.
#include <iostream>
#include <string.h>
#include <vector>
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s =
"1111011110000011100000110001011011110010111001010111110001";
long int count = 0, size;
unsigned long long int dec = 0;
size = s.size();
// cout << s[size - 1] << endl;
for (int i = 0; i < size; i++)
{
// cout << pow(2, size - i - 1) << endl;
if (s[i] == '0')
continue;
// cout<<int(s[i])-48<<endl;
dec += (int(s[i]) - 48) * pow(2, size - 1 - i);
}
// cout << dec << endl;
// dec = 278675673186014705;
while (dec != 1)
{
if (dec % 2 == 0)
dec /= 2;
else
dec += 1;
count += 1;
}
cout << count;
return 0;
}
This line:
pow(2, size - 1 - i)
Can face precision errors as pow takes and returns doubles.
Luckily, for powers base 2 that won't overflow unsigned long longs, we can simply use bit shift (which is equivalent to pow(2, x)).
Replace that line with:
1LL<<(size - 1 - i)
So that it should look like this:
dec += (int(s[i]) - 48) * 1ULL<<(size - 1 - i);
And we will get the correct output of 85.
Note: as mentioned by #RSahu, you can remove (int(s[i]) - 48), as the case where int(s[i]) == '0' is already caught in an above if statement. Simply change the line to:
dec += 1ULL<<(size - 1 - i);
The core problem has already been pointed out in answer by #Ryan Zhang.
I want to offer some suggestions to improve your code and make it easier to debug.
The main function has two parts -- first part coverts a string to number and the second part computes the number of steps to get the number to 1. I suggest creating two helper functions. That will allow you to debug each piece separately.
int main()
{
string s = "1111011110000011100000110001011011110010111001010111110001";
unsigned long long int dec = stringToNumber(s);
cout << "Number: " << dec << endl;
// dec = 278675673186014705;
int count = getStepsTo1(dec);
cout << "Steps to 1: " << count << endl;
return 0;
}
Iterate over the string from right to left using std::string::reverse_iterator. That will obviate the need for size and use of size - i - 1. You can just use i.
unsigned long long stringToNumber(string const& s)
{
size_t i = 0;
unsigned long long num = 0;
for (auto it = s.rbegin(); it != s.rend(); ++it, ++i )
{
if (*it != '0')
{
num += 1ULL << i;
}
}
return num;
}
Here's the other helper function.
int getStepsTo1(unsigned long long num)
{
long int count = 0;
while (num != 1 )
{
if (num % 2 == 0)
num /= 2;
else
num += 1;
count += 1;
}
return count;
}
Working demo: https://ideone.com/yerRfK.
I am stuck on a project where I have to print out any number in any base from 10-16. The problem is that in those bases, you have to add a letter to the front, which I don't really understand how to do with recursion. Can anyone help me?
int conversionFunction(int num, int base)
{
if (num == 0)
return 0;
int x = num % base;
num /= base;
if (x < 0)
num = num + 1;
conversionFunction(num, base);
if (x < 0){
cout << x+(base * -1);
}
else{
cout << x;
return x;
}
}
If I do 246 in base 16, I get 156. I know that the actual answer should be F6. 15 translates to F when converting. But how would I do that?
Something like
static const char* digits = "0123456789abcdef";
and
cout << digits[num % base];
is a nice way. static just means that digits is has global lifetime but is scoped to your function (basically, you won't have to recreate it over and over every time you enter your function).
You seem to be stuck just on the problem of converting between bases. I can think of two ways to do it:
Divide by decreasing powers of the radix, from n-1 to 0, where n is the largest power. That requires you to know the largest value that you might have to convert. Each division gives you a digit in the place that corresponds to that power. Using your example, you could decide to go up to four digits, so you'd have:
246 / 16^^3 = 0
246 / 16^^2 = 0
246 / 16^^1 = F
6 / 16^^0 = 6
So the answer is 0x00F6.
Use modulo arithmetic with increasing powers of the radix, from 1 to n. Again, each operation gives you a digit in the place that corresponds to the power of the radix. Using the same example:
246 mod 16^^1 = 6
240 mod 16^^2 = F
So again, you've got 0xF6.
Here's a version with comments in the code using a similar approach as in okovkos answer and Calebs second solution. It starts with the least significant digit and extracts until num is zero. It supports conversions in the range (INTMAX_MIN, INTMAX_MAX] using a base in the range [2, 36].
#include <iostream>
#include <string>
#include <cstdint> // std::intmax_t, std::uintmax_t
std::string itos(
std::intmax_t num, // number to convert, range: (INTMAX_MIN, INTMAX_MAX]
const int base=10, // base, range: [2, 36]
const std::string& prefix="", // user defined prefix
bool add_plus=false) // add plus sign for positive numbers
{
static const std::string digits = "0123456789abcdefghijklmnopqrstuvwxyz";
if(base>36 || base<2) return ""; // erroneous base
std::string rv; // the return value we'll create
if(num) {
bool negative = false;
if(num<0) {
if(num==INTMAX_MIN) return ""; // the ONE std::intmax_t number you can't use
// make it positive for the calculation
num = -num;
negative = true;
}
std::uintmax_t x;
while(num) {
x = num % base; // extract least significant digits index
rv.insert(rv.begin(), digits[x]); // insert digit first
num -= x; // reduce num with the extracted value
num /= base; // divide num down for next extraction
}
// the below two inserts could be moved to just before the
// return if you want to add the prefix for the value zero too
// insert prefix
rv.insert(0, prefix);
// insert minus sign if negative or plus if desired
if(negative) rv.insert(rv.begin(), '-');
else if(add_plus) rv.insert(rv.begin(), '+');
} else rv = "0"; // special case
return rv;
}
int main() {
std::cout << "bin " << itos(255, 2, "0b") << "\n";
std::cout << "oct " << itos(255, 8, "0") << "\n";
std::cout << "dec " << itos(255, 10, "", true) << "\n";
std::cout << "hex " << itos(-INTMAX_MAX, 16, "0x") << "\n";
std::cout << "hex " << itos(INTMAX_MAX, 16, "0x") << "\n";
}
Possible output:
bin 0b11111111
oct 0377
dec +255
hex -0x7fffffffffffffff
hex 0x7fffffffffffffff
hey guys I am trying to calculate pi using this formula:
pi = 4 ยท [ 1 โ 1/3 + 1/5 โ 1/7 + 1/9 ... + (โ1)^n/(2n + 1) ]
yet i always get a zero for my output pi value and I am really confused as to where I had gone wrong. Here is my code:
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
int n;
double b = 0;
char c = 'Y';
int s = 1;
while (c == 'Y') {
cout << "Enter the value of the parameter 'n' in the Leibniz formula (or -1 to quit):" << endl;
cin >> n;
if (n != -1) {
c = 'Y';
for (int a = 1; a <= n; a++) {
s = -s;
b += 4 * (s/ (2 * a + 1));
}
cout << "The approximate value of pi using 1 term is:" << b << endl;
}
else {
c = 'N';
}
}
return 0;
}
In both C and C++, mathematical operations on integers result in an integer even if the result would be fractional in conventional mathematics. Change your int to a float or double and I suspect that it will work better.
The result is truncated to the integer value and has an integer type.
So for example: 2 / 4 results in 0 and 5 / 2 would result in 2.
NOTE if you perform an operation between a floating point value and an integer value, the result is a floating point value. So:
2.0 / 4 == 0.5
Your code seems to be complicated and int type is used in places where floating operations are expected.
Consider the following simplified example:
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
int n = 0;
double b = 0;
double s = 1; // Tytpe is changed
while (n != -1) { // there is no need for char c
cout << "Enter the value of the parameter 'n' in the Leibniz formula (or -1 to quit):" << endl;
cin >> n;
b = 0; // init b before starting the loop
s = 1; // the same for s (it can be -1 from the next user input)
// there is no need for if (n != -1) because for has condition
for (int a = 1; a <= n; a++) {
s = -s;
b += 4 * (s / (2.0 * a + 1));
}
cout << "The approximate value of pi using 1 term is:" << b << endl;
}
return 0;
}
IMPORTANT UPDATE:
To make your calculation correct (in terms of Leibniz's formula) I suggest the following changes in the for loop:
for (int a = 0; a <= n; a+=2) { // start from 0 with step 2
b += 4.0 * (s / (a + 1.0));
s = -s; // change the sign for next calculation
}
and further, consider some kind of optimization
b = 0; // do not forget about reseting b to 0 before making sum
s = 1; // set 1 in the sign
for (int a = 0; a <= n; a+=2) { // start from 0 with step 2
b += s / (a + 1.0); // no multiplication on each iteration
s = -s; // because s was initialized with 1
}
b *= 4.0; // multiply once for the whole sum
UPDATE 2
For case if precision is really important for output, final snippet can be like:
#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n = 0;
double b = 0;
double s = 1;
int prec = 0;
cout << "What precision should be used for output? (Value from 1 to 10): ";
while (prec< 1 || prec > 10)
{
cin >> prec;
}
while (true) {
cout << "Enter the value of the parameter 'n' in the Leibniz formula (or -1 to quit):" << endl;
cin >> n;
if (n == -1)
{
break; // go out the loop if user enter -1 (want to exit)
}
else if (n <= 0)
{
cout << "'n' have to be 1 or greater" << endl;
continue; // go to the next iteration to ask new 'n'
}
s = 1;
b = 1.0; // we can start from 1 (no need to claculate the first term) and make loop from 2
for (int a = 2; a < n*2; a+=2) { // start from 2 with step 2 (so n should be doubled)
s = -s; // change the sign for this iteration, because now loop started from a = 2
b += s / (a + 1.0);
}
b *= 4.0;
cout << "The approximate value of pi using 1 term is: " << setprecision(prec+1) << b << " (PI = " << M_PI << ")" << endl;
}
return 0;
}
Note:
In this version b initialized with 1.0 because the first item in the Leibniz series is always 1 (we can skip calculation, but we should change the logic for sign changes - make s = -1; or move s = -s; before summation - I choose the 2nd option).
Also I'am not sure what is "parameter 'n' in the Leibniz formula", so pay attention to condition of for loop - now (with a < n*2) it is correct for case if n is number of items in the Leibniz series to be calculated.
Along with doing integer math, you have a few other minor problems.
First, the formula is [1 - ...], not [0 - ...], so you need to initialize b to 1.0, not 0.
Second, it's supposed to be 4 * [...], but you're multiplying by 4 on every iteration of the loop, so you're getting `[0 - b1 * 4 + b2 * 4 -b3 * 4 ....].
You can distribute the multiplication if you want to, but if you do you'll need to distribute it correctly (e.g., the starting value of 1.0 would also need to be multiplied by 4).
Also note that you're not re-initializing correctly, so the second (and subsequent) times you attempt to re-compute the value, you'll get completely incorrect answers (until you fix more stuff).
You've been burned by integer division.
b += 4 * (s/ (2 * a + 1));
a is an int so the division result is an int.
A cast to double will fix it:
b += 4 * (s/ (2 * double(a) + 1));
I'm working on a program that will allow me to multiply/divide/add/subtract binary numbers together. In my program I'm making all integers be represented as vectors of digits.
I've managed to figure out how to do this with addition, however multiplication has got me stumbled and I was wondering if anyone could give me some advice on how to get the pseudo code as a guide for this program.
Thanks in advance!
EDIT: I'm trying to figure out how to create the algorithm for multiplication still to clear things up. Any help on how to figure this algorithm would be appreciated. I usually don't work with C++, so it takes me a bit longer to figure things out with it.
You could also consider the Booth's algorithm if you'd like to multiply:
Booth's multiplication algorithm
Long multiplication in pseudocode would look something like:
vector<digit> x;
vector<digit> y;
total = 0;
multiplier = 1;
for i = x->last -> x->first //start off with the least significant digit of x
total = total + i * y * multiplier
multiplier *= 10;
return total
you could try simulating a binary multiplier or any other circuit that is used in a CPU.
Just tried something, and this would work if you only multiply unsigned values in binary:
unsigned int multiply(unsigned int left, unsigned int right)
{
unsigned long long result = 0; //64 bit result
unsigned int R = right; //32 bit right input
unsigned int M = left; //32 bit left input
while (R > 0)
{
if (R & 1)
{// if Least significant bit exists
result += M; //add by shifted left
}
R >>= 1;
M <<= 1; //next bit
}
/*-- if you want to check for multiplication overflow: --
if ((result >> 32) != 0)
{//if has more than 32 bits
return -1; //multiplication overflow
}*/
return (unsigned int)result;
}
However, that's at the binary level of it... I just you have vector of digits as input
I made this algorithm that uses a binary addition function that I found on the web in combination with some code that first adjusts "shifts" the numbers before sending them to be added together.
It works with the logic that's in this video https://www.youtube.com/watch?v=umqLvHYeGiI
and this is the code:
#include <iostream>
#include <string>
using namespace std;
// This function adds two binary strings and return
// result as a third string
string addBinary(string a, string b)
{
string result = ""; // Initialize result
int s = 0; // Initialize digit sum
int flag =0;
// Traverse both strings starting from last
// characters
int i = a.size() - 1, j = b.size() - 1;
while (i >= 0 || j >= 0 || s == 1)
{
// Computing the sum of the digits from right to left
//x = (condition) ? (value_if_true) : (value_if_false);
//add the fire bit of each string to digit sum
s += ((i >= 0) ? a[i] - '0' : 0);
s += ((j >= 0) ? b[j] - '0' : 0);
// If current digit sum is 1 or 3, add 1 to result
//Other wise it will be written as a zero 2%2 + 0 = 0
//and it will be added to the heading of the string (to the left)
result = char(s % 2 + '0') + result;
// Compute carry
//Not using double so we get either 1 or 0 as a result
s /= 2;
// Move to next digits (more to the left)
i--; j--;
}
return result;
}
int main()
{
string a, b, result= "0"; //Multiplier, multiplicand, and result
string temp="0"; //Our buffer
int shifter = 0; //Shifting counter
puts("Enter you binary values");
cout << "Multiplicand = ";
cin >> a;
cout<<endl;
cout << "Multiplier = ";
cin >> b;
cout << endl;
//Set a pointer that looks at the multiplier from the bit on the most right
int j = b.size() - 1;
// Loop through the whole string and see if theres any 1's
while (j >= 0)
{
if (b[j] == '1')
{
//Reassigns the original value every loop to delete the old shifting
temp = a;
//We shift by adding zeros to the string of bits
//If it is not the first iteration it wont add any thing because we did not "shift" yet
temp.append(shifter, '0');
//Add the shifter buffer bits to the result variable
result = addBinary(result, temp);
}
//we shifted one place
++shifter;
//move to the next bit on the left
j--;
}
cout << "Result = " << result << endl;
return 0;
}
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
An interview question:
Make a program which takes input 'N'(unsigned long) and prints two columns, 1st column prints numbers from 1 to N (in hexadecimal format) and second column prints the number of 1s in the binary representation of the number in the left column. Condition is that this program should not count 1s (so no computations 'per number' to get 1s/ no division operators).
I tried to implement this by leveraging fact that No of 1s in 0x0 to 0xF can be re-used to generate 1s for any number. I am pasting code ( basic one without error checking.) Its giving correct results but I am not happy with space usage. How can I improve on this?
( Also I am not sure if its what interviewer was looking for).
void printRangeFasterWay(){
uint64_t num = ~0x0 ;
cout << " Enter upper number " ;
cin >> num ;
uint8_t arrayCount[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4} ;
// This array will store information needed to print
uint8_t * newCount = new uint8_t[num] ;
uint64_t mask = 0x0 ;
memcpy(newCount, &arrayCount[0], 0x10) ;
uint64_t lower = 0;
uint64_t upper = 0xF;
uint64_t count = 0 ;
uint32_t zcount= 0 ;
do{
upper = std::min(upper, num) ;
for(count = lower ; count <= upper ; count++){
newCount[count] = (uint32_t)( newCount[count & mask] + newCount[(count & ~mask)>>(4*zcount)]) ;
}
lower += count ;
upper |= (upper<<4) ;
mask = ((mask<<4) | 0xF ) ;
zcount++ ;
}while(count<=num) ;
for(uint64_t xcount=0 ; xcount <= num ; xcount++){
cout << std::hex << " num = " << xcount << std::dec << " number of 1s = " << (uint32_t)newCount[xcount] << endl;
}
}
Edited to add sample run
Enter upper number 18
num = 0 number of 1s = 0
num = 1 number of 1s = 1
num = 2 number of 1s = 1
num = 3 number of 1s = 2
num = 4 number of 1s = 1
num = 5 number of 1s = 2
num = 6 number of 1s = 2
num = 7 number of 1s = 3
num = 8 number of 1s = 1
num = 9 number of 1s = 2
num = a number of 1s = 2
num = b number of 1s = 3
num = c number of 1s = 2
num = d number of 1s = 3
num = e number of 1s = 3
num = f number of 1s = 4
num = 10 number of 1s = 1
num = 11 number of 1s = 2
num = 12 number of 1s = 2
I have a slightly different approach which should solve your memory problem. Its based on the fact that the bitwise operation i & -i gives you the smallest power of two in the number i. For example, for i = 5, i & -i = 1, for i = 6, i & -i = 2. Now, for code:
void countBits(unsigned N) {
for (int i = 0;i < N; i ++)
{
int bits = 0;
for (int j = i; j > 0; j= j - (j&-j))
bits++;
cout <<"Num: "<<i <<" Bits:"<<bits<<endl;
}
}
I hope I understood your question correctly. Hope that helps
Edit:
Ok, try this - this is dynamic programming without using every bit in every number:
void countBits(unsigned N) {
unsigned *arr = new unsigned[N + 1];
arr[0]=0;
for (int i = 1;i <=N; i ++)
{
arr[i] = arr[i - (i&-i)] + 1;
}
for(int i = 0; i <=N; i++)
cout<<"Num: "<<i<<" Bits:"<<arr[i]<<endl;
}
Hopefully, this works better
Several of the answers posted so far make use of bit shifting (just another word for division by 2) or
bit masking. This stikes me as a bit of a cheat. Same goes for using the '1' bit count in a 4 bit pattern then
matching by chunks of 4 bits.
How about a simple recursive solution using an imaginary binary tree of bits. each left branch contains a '0', each
right branch contains a '1'. Then do a depth first traversal counting the number of 1 bits on the way down. Once
the bottom of the tree is reached add one to the counter, print out the number of 1 bits found so far, back out
one level and recurse again.
Stop the recursion when the counter reaches the desired number.
I am not a C/C++ programmer, but here is a REXX solution that should translate without much imagination. Note
the magic number 32 is just the number of bits in an Unsigned long. Set it to anything
/* REXX */
SAY 'Stopping number:'
pull StopNum
Counter = 0
CALL CountOneBits 0, 0
return
CountOneBits: PROCEDURE EXPOSE Counter StopNum
ARG Depth, OneBits
If Depth = 32 then Return /* Number of bits in ULong */
if Counter = StopNum then return /* Counted as high as requested */
call BitCounter Depth + 1, OneBits /* Left branch is a 0 bit */
call BitCounter Depth + 1, OneBits + 1 /* Right branch is a 1 bit */
Return
BitCounter: PROCEDURE EXPOSE Counter StopNum
ARG Depth, OneBits
if Depth = 32 then do /* Bottom of binary bit tree */
say D2X(Counter) 'contains' OneBits 'one bits'
Counter = Counter + 1
end
call CountOneBits Depth, OneBits
return
Results:
Stopping number:
18
0 contains 0 one bits
1 contains 1 one bits
2 contains 1 one bits
3 contains 2 one bits
4 contains 1 one bits
5 contains 2 one bits
6 contains 2 one bits
7 contains 3 one bits
8 contains 1 one bits
9 contains 2 one bits
A contains 2 one bits
B contains 3 one bits
C contains 2 one bits
D contains 3 one bits
E contains 3 one bits
F contains 4 one bits
10 contains 1 one bits
11 contains 2 one bits
This answer is resonably efficient in time and space.
Can be done relatively trivially in constant time with the appropriate bit switching. No counting of 1s and no divisions. I think you were on the right track with keeping the array of known bit values:
int bits(int x)
{
// known bit values for 0-15
static int bc[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
// bit "counter"
int b = 0;
// loop iterator
int c = 0;
do
{
// get the last 4 bits in the number
char lowc = static_cast<char>(x & 0x0000000f);
// find the count
b += bc[lowc];
// lose the last four bits
x >>= 4;
++c;
// loop for each possible 4 bit combination,
// or until x is 0 (all significant bits lost)
}
while(c < 8 && x > 0);
return b;
}
Explanation
The following algorithm is like yours, but expands on the idea (if I understood your approach correctly.) It does not do any computation 'per number' as directed by the question, but instead uses a recursion that exists between sequences of lengths that are powers of 2. Basically, the observation is that for the sequence 0, 1,..,2^n-1 , we can use the sequence 0, 1, ...,2^(n-1)-1 in the following way.
Let f(i) be the number of ones in number i then f(2^(n-1)+i)=f(i)+1 for all 0<=i<2^(n-1). (Verify this for yourself)
Algorithm in C++
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
const int N = 32;
int* arr = new int[N];
arr[0]=0;
arr[1]=1;
for ( int i = 1; i < 15; i++ )
{
int pow2 = 1 << i;
int offset = pow2;
for ( int k = 0; k < pow2; k++ )
{
if ( offset+k >= N )
goto leave;
arr[offset+k]=arr[k]+1;
}
}
leave:
for ( int i = 0; i < N; i++ )
{
printf( "0x%8x %16d", i, arr[i] );
}
delete[] arr;
return EXIT_SUCCESS;
}
Note that in the for loop
for ( int i = 0; i < 15; i++ )
there may be overflow into negative numbers if you go higher than 15, otherwise use unsigned int's if you want to go higher than that.
Efficiency
This algorithm runs in O(N) and uses O(N) space.
Here is an approach that has O(nlogn) time complexity and O(1) memory usage. The idea is to get the Hex equivalent of the number and iterate over it to get number of ones per Hex digit.
int oneCount[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
int getOneCount(int n)
{
char inStr[70];
sprintf(inStr,"%X",n);
int i;
int sum=0;
for(i=0; inStr[i];i++)
{
if ( inStr[i] > '9' )
sum += oneCount[inStr[i]-'A' + 10];
else
sum+= oneCount[inStr[i] -'0'];
}
return sum;
}
int i,upperLimit;
cin>>upperLimit;
for(i=0;i<=upperLimit;i++)
{
cout << std::hex << " num = " << i << std::dec << " number of 1s = " << getOneCount(i) << endl;
}
enum bit_count_masks32
{
one_bits= 0x55555555, // 01...
two_bits= 0x33333333, // 0011...
four_bits= 0x0f0f0f0f, // 00001111....
eight_bits= 0x00ff00ff, // 0000000011111111...
sixteen_bits= 0x0000ffff, // 00000000000000001111111111111111
};
unsigned int popcount32(unsigned int x)
{
unsigned int result= x;
result= (result & one_bits) + (result & (one_bits << 1)) >> 1;
result= (result & two_bits) + (result & (two_bits << 2)) >> 2;
result= (result & four_bits) + (result & (four_bits << 4)) >> 4;
result= (result & eight_bits) + (result & (eight_bits << 8)) >> 8;
result= (result & sixteen_bits) + (result & (sixteen_bits << 16)) >> 16;
return result;
}
void print_range(unsigned int low, unsigned int high)
{
for (unsigned int n= low; unsigned int n<=high; ++n)
{
cout << std::hex << " num = " << xcount << std::dec << " number of 1s = " << popcount32(n) << endl;
}
}