Related
Intro:
I have a homework assignment to create a type for "ints larger than existing types can store."
We should store the numbers in an array of digits(backward for easier math logic).
I'm using a dynamic array to store the info in the object.
I am required to overload at least the +, -, * , <, >, << and >> operators.
Also .cpp and .h files must be separate.
Problem:
Not too sure how to overload the >> operator based on the class attributes and manipulation needed.
BigIntegers.h
#include <string>
#include <iostream>
typedef int* BigIntPtr;
class BigIntegers {
private:
int size; // based on string size, if neg string size -1
BigIntPtr number; // dynamic array ptr
bool isNeg; // set default to false, assumes a positive number
public:
explicit BigIntegers(std::string num = "");
BigIntegers(const BigIntegers &bi);
~BigIntegers();
friend std::istream &operator>>(std::istream &is, BigIntegers &bi) {
/**
* using eg "is >> bi.data;" doesn't seem viable given the data manipulation needed
* see constructor
*/
std::string input;
getline(is,input);
bi = BigIntegers(input);
return is;
}
friend std::ostream &operator<<(std::ostream &os, const BigIntegers &bi) {
if(bi.isNeg) //add sign if needed
os << '-';
for(int s=bi.size-1;s>-1;s--) //print reverse
{
os << bi.number[s];
}
return os;
}
};
BigIntegers.cpp
#include <algorithm>
#include "BigIntegers.h"
BigIntegers::BigIntegers(std::string num) {
//if null
if(num.empty())
{
size = 0;
number = NULL;
isNeg = 0;
return;
}
//determine if its negative
if (num.find('-') == 0)
{
num.erase(remove(num.begin(),num.end(), '-'),num.end());
isNeg =true;
}else {isNeg= false;}
size = num.length();
number = new int[size];
//add array backwards for math optimization
std::string rev; rev.assign(num.rbegin(),num.rend());
for(int i = 0; i < size; i++)
{
number[i]=rev[i]-'0';
}
}
BigIntegers::~BigIntegers() {
delete [] number;
size =0;
isNeg =0;
}
#include <iostream>
#include "BigIntegers.h"
using std::cout;
using std::cin;
using std::string;
int main() {
//basic functionality test
string stringInt = "123456";
string stringIntNeg = "-99987654321";
BigIntegers test1(stringInt);
cout << test1 << "\n";
BigIntegers test2(stringIntNeg);
cout << test2 << "\n";
//iostream test
cout << "Enter a big integer in the form 123456 or -123456.\n";
BigIntegers test3;
cin >> test3;
cout << test3 << "\n";
return 0;
}
output
pr4_bigIntegers\cmake-build-debug\pr4_bigIntegers.exe
123456
-12345678987654321
Enter a big integer in the form 123456 or -123456.
5789256
-57883070081-2144186072
Process finished with exit code 0
Note:
Additionally, sometimes the output is almost correct but negative or some other garbage values are included. eg) cin >> 5314 , cout <<-5314
edit - I've realized that after 4 digits the garbage is introduced. The experimentation continues.
Assignment Instructions - (for additional context, this is a direct copy/paste)
The existing types of integers in C++ cannot store very large integers. We need a new type that can store these large integers we possibly need in dealing with scientific problems.
You can represent an integer by storing the integer as an array of digits.
Design and implement a class for integer arithmetic in which a number is implemented as an array of digits. Each entry of the array will be a digit from 0 to 9 (inclusive).
The number represented is the concatenation of the digits in the array.
You are required to overload at least the +, -, * , <, >, << and >> operators for this class. Try to overload the division operator /.
Do not forget to implement the gang of three: assignment operator, copy constructor and destructor.
Your division operator is an integer operator so that it returns the integer part of the quotient. You need to understand that the purpose of this class is to store large integers so you should not convert your array representation into regular integer representation during the process of overloading these operators. Again, we assume that these integers cannot be handled by using the build-in integer types so your explicit constructor should have a string type parameter, not an integer type parameter, and get each character from the string, convert it to a digit and store it to your array. To perform operations easily, you may want to store an integer in reversed order in your array.
Use dynamic array to store your integer.
Include professional documentation of your code and proper indentation
Separate your header file from implementation file
Test every aspect of your class.
Email clarification from teacher
Just answer a couple of questions from some of you.
The integers are signed because when you do your subtraction you may get a negative integer. So use the first spot of the array to store 0 or 1 (0 for negative and 1 for positive).
The instructions do not allow you to convert the string parameter to an integer. I mean that you should not convert string s="123456" to int n=123456. But, you have to convert character 1 into integer 1, ..., character 6 into integer 6 and store each into your array.
Your overloaded >> operator seems to be correct.
Your second problem: The minus sign is no garbage.
bool isNeg; // set default to false, assumes a positive number
You never set it to false. I debugged your code, and the solution is simple:
BigIntegers::BigIntegers(std::string num) : isNeg(false) {
//your constructor stuff
}
I suggest using a dynamic array of type unsigned short instead.
Saving each digit in an integer each ranging from -2.14 Billion to 2.14 Billion is overkill will require a lot of memory. You don't need negative values to store. You may consider using chars, as you can convert each integer digit into a char and backward but less memory is required. The most memory-efficient way is perhaps an Enum ranging from 0 to 9.
Your class would require storing a number greater than a long long (8 bytes) at least 64 bytes (number array) + 4 bytes for the size variable + 1 bit (isNeg). This is quite large for a number :)
According to your task, you are not allowed to use integers. So you have to change it :)
My approach exploits the fact that each element of an enum class can be converted to an integer type according to its index in the enum class definition (and vice versa). Eventually, each integer can be converted to a char. Thus, there are still integers but you can spot them hardly.
enum class Digit{Zero,One,Two,Three,Four,Five,Six,Seven,Eight,Nine};
typedef Digit* BigIntPtr;
class BigIntegers
{
public:
explicit BigIntegers(std::string num = "");
BigIntegers(const BigIntegers& src);
BigIntegers& operator=(const BigIntegers&src);
~BigIntegers();
friend bool operator<(const BigIntegers& lhs, const BigIntegers& rhs);
friend bool operator>(const BigIntegers& lhs, const BigIntegers& rhs);
friend BigIntegers operator+(const BigIntegers& lhs, const BigIntegers& rhs);
friend BigIntegers operator-(const BigIntegers& lhs, const BigIntegers&rhs);
friend std::istream &operator>>(std::istream &is, BigIntegers &bi);
friend std::ostream &operator<<(std::ostream &os, const BigIntegers &bi);
private:
size_t size; // based on string size, if neg string size -1
BigIntPtr number; // dynamic array ptr
bool isNeg; // set default to false, assumes a positive number
};
Your .cpp file:
#include <algorithm>
#include "bigint.h"
using namespace std;
BigIntegers::BigIntegers(std::string num):isNeg(false)
{
//if null
if (num.empty())
{
size = 0;
number = NULL;
isNeg = 0;
return;
}
//determine if its negative
if (num.find('-') == 0)
{
num.erase(remove(num.begin(), num.end(), '-'), num.end());
isNeg = true;
}
size = num.length();
number = new Digit[size];
//add array backwards for math optimization
std::string rev; rev.assign(num.rbegin(), num.rend());
Digit * aux = number;
std::for_each (rev.begin(),rev.end(),[&](const char c)
{
*number = Digit(c - '0');
number++;
});
number = aux;
}
BigIntegers::BigIntegers(const BigIntegers & src)
: size(src.size), number{new Digit[src.size]}, isNeg(src.isNeg)
{
for (auto i = number, j = src.number; i < number + size; i++, j++)
{
*i = *j;
}
}
BigIntegers & BigIntegers::operator=(const BigIntegers & src)
{
if (this == &src)
return *this;
size = src.size;
isNeg = src.isNeg;
if (number != NULL) delete[] number;
number = new Digit[src.size];
for (auto i = number, j = src.number; i < number + size; i++,j++)
{
*i = *j;
}
return *this;
}
BigIntegers::~BigIntegers()
{
delete[] number;
}
bool operator<(const BigIntegers & lhs, const BigIntegers & rhs)
{
if (lhs.size > rhs.size) return false;
if (lhs.size < rhs.size) return true;
for (auto i = lhs.number + lhs.size - 1, j = rhs.number + rhs.size - 1; i >= lhs.number || j >= rhs.number; i--, j--)
{
if (char(*i) > char(*j))return false;
if (char(*i) < char(*j))return true;
}
return false;
}
bool operator>(const BigIntegers & lhs, const BigIntegers & rhs)
{
return !(lhs < rhs);
}
BigIntegers operator+(const BigIntegers & lhs, const BigIntegers & rhs)
{
string value = "";
Digit aux = Digit::Zero;
for (auto i = lhs.number, j = rhs.number; i < lhs.number + lhs.size || j < rhs.number + rhs.size; i++, j++)
{
char c = char(aux);
c += i < lhs.number + lhs.size ? char(*i) : char(0);
c += j < rhs.number + rhs.size ? char(*j) : char(0);
aux = Digit(0);
if (c > 9)
{
aux = Digit::One;
c -= 10;
}
// 48 is '0' in Ascii table
value += (c+48);
}
if (aux == Digit::One)
{
value += '1';
}
reverse(value.begin(), value.end());
return BigIntegers(value);
}
BigIntegers operator-(const BigIntegers & lhs, const BigIntegers & rhs)
{
bool reverse = false;
if (lhs < rhs)reverse = true;
const BigIntegers& bigger = reverse ? rhs : lhs;
const BigIntegers& smaller = reverse ? lhs : rhs;
Digit aux = Digit::Zero;
std::string value = "";
for (auto i = bigger.number, j = smaller.number; i < bigger.number+bigger.size; i++, j++)
{
char c1 = char(*i);
char c2 = j < smaller.number+smaller.size ? char(*j) : 0;
c2 += char(aux);
aux = Digit::Zero;
if (c1 < c2)
{
aux = Digit::One;
c1 = c1 + 10 - c2;
}
else
{
c1 -= c2;
}
if (c1 > 0 || i < bigger.number + bigger.size - 1)
{
// if condition is to avoid leading zeros
value += (c1 + 48);
}
}
if (reverse)value += "-";
std::reverse(value.begin(), value.end());
return BigIntegers(value);
}
istream& operator>>(istream& is, BigIntegers& bi)
{
std::string input;
getline(is, input);
bi = BigIntegers(input);
return is;
}
std::ostream &operator<<(std::ostream &os, const BigIntegers &bi) {
if (bi.isNeg) //add sign if needed
os << '-';
for (int s = bi.size - 1; s > -1; s--) //print reverse
{
os << static_cast<int>(bi.number[s]);
}
return os;
}
As you may notice, I replaced all for loops using an integer ;)
At least I am not using the int keyword once. However, something like +10 is of course a const integer.
Up to this point, I have not yet been able to determine that storing the digits in reverse is advantageous.
The multiplication is up to you. Nice task :)
This overload is what solved the problem of the garbage values.
BigIntegers &BigIntegers::operator=(const BigIntegers &bi) {
//if number is already assigned here
if(this==&bi)
return *this;
//else assign the number
size = bi.size; isNeg = bi.isNeg;
if (number != nullptr) delete[] number;
number= new int[bi.size];
for (auto i = number, j = bi.number; i < number+size; i++, j++)
*i = *j;
return *this;
}
I have a vector with digits of number, vector represents big integer in system with base 2^32. For example:
vector <unsigned> vec = {453860625, 469837947, 3503557200, 40}
This vector represent this big integer:
base = 2 ^ 32
3233755723588593872632005090577 = 40 * base ^ 3 + 3503557200 * base ^ 2 + 469837947 * base + 453860625
How to get this decimal representation in string?
Here is an inefficient way to do what you want, get a decimal string from a vector of word values representing an integer of arbitrary size.
I would have preferred to implement this as a class, for better encapsulation and so math operators could be added, but to better comply with the question, this is just a bunch of free functions for manipulating std::vector<unsigned> objects. This does use a typedef BiType as an alias for std::vector<unsigned> however.
Functions for doing the binary division make up most of this code. Much of it duplicates what can be done with std::bitset, but for bitsets of arbitrary size, as vectors of unsigned words. If you want to improve efficiency, plug in a division algorithm which does per-word operations, instead of per-bit. Also, the division code is general-purpose, when it is only ever used to divide by 10, so you could replace it with special-purpose division code.
The code generally assumes a vector of unsigned words and also that the base is the maximum unsigned value, plus one. I left a comment wherever things would go wrong for smaller bases or bases which are not a power of 2 (binary division requires base to be a power of 2).
Also, I only tested for 1 case, the one you gave in the OP -- and this is new, unverified code, so you might want to do some more testing. If you find a problem case, I'll be happy to fix the bug here.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
namespace bigint {
using BiType = std::vector<unsigned>;
// cmp compares a with b, returning 1:a>b, 0:a==b, -1:a<b
int cmp(const BiType& a, const BiType& b) {
const auto max_size = std::max(a.size(), b.size());
for(auto i=max_size-1; i+1; --i) {
const auto wa = i < a.size() ? a[i] : 0;
const auto wb = i < b.size() ? b[i] : 0;
if(wa != wb) { return wa > wb ? 1 : -1; }
}
return 0;
}
bool is_zero(BiType& bi) {
for(auto w : bi) { if(w) return false; }
return true;
}
// canonize removes leading zero words
void canonize(BiType& bi) {
const auto size = bi.size();
if(!size || bi[size-1]) return;
for(auto i=size-2; i+1; --i) {
if(bi[i]) {
bi.resize(i + 1);
return;
}
}
bi.clear();
}
// subfrom subtracts b from a, modifying a
// a >= b must be guaranteed by caller
void subfrom(BiType& a, const BiType& b) {
unsigned borrow = 0;
for(std::size_t i=0; i<b.size(); ++i) {
if(b[i] || borrow) {
// TODO: handle error if i >= a.size()
const auto w = a[i] - b[i] - borrow;
// this relies on the automatic w = w (mod base),
// assuming unsigned max is base-1
// if this is not the case, w must be set to w % base here
borrow = w >= a[i];
a[i] = w;
}
}
for(auto i=b.size(); borrow; ++i) {
// TODO: handle error if i >= a.size()
borrow = !a[i];
--a[i];
// a[i] must be set modulo base here too
// (this is automatic when base is unsigned max + 1)
}
}
// binary division and its helpers: these require base to be a power of 2
// hi_bit_set is base/2
// the definition assumes CHAR_BIT == 8
const auto hi_bit_set = unsigned(1) << (sizeof(unsigned) * 8 - 1);
// shift_right_1 divides bi by 2, truncating any fraction
void shift_right_1(BiType& bi) {
unsigned carry = 0;
for(auto i=bi.size()-1; i+1; --i) {
const auto next_carry = (bi[i] & 1) ? hi_bit_set : 0;
bi[i] >>= 1;
bi[i] |= carry;
carry = next_carry;
}
// if carry is nonzero here, 1/2 was truncated from the result
canonize(bi);
}
// shift_left_1 multiplies bi by 2
void shift_left_1(BiType& bi) {
unsigned carry = 0;
for(std::size_t i=0; i<bi.size(); ++i) {
const unsigned next_carry = !!(bi[i] & hi_bit_set);
bi[i] <<= 1; // assumes high bit is lost, i.e. base is unsigned max + 1
bi[i] |= carry;
carry = next_carry;
}
if(carry) { bi.push_back(1); }
}
// sets an indexed bit in bi, growing the vector when required
void set_bit_at(BiType& bi, std::size_t index, bool set=true) {
std::size_t widx = index / (sizeof(unsigned) * 8);
std::size_t bidx = index % (sizeof(unsigned) * 8);
if(bi.size() < widx + 1) { bi.resize(widx + 1); }
if(set) { bi[widx] |= unsigned(1) << bidx; }
else { bi[widx] &= ~(unsigned(1) << bidx); }
}
// divide divides n by d, returning the result and leaving the remainder in n
// this is implemented using binary division
BiType divide(BiType& n, BiType d) {
if(is_zero(d)) {
// TODO: handle divide by zero
return {};
}
std::size_t shift = 0;
while(cmp(n, d) == 1) {
shift_left_1(d);
++shift;
}
BiType result;
do {
if(cmp(n, d) >= 0) {
set_bit_at(result, shift);
subfrom(n, d);
}
shift_right_1(d);
} while(shift--);
canonize(result);
canonize(n);
return result;
}
std::string get_decimal(BiType bi) {
std::string dec_string;
// repeat division by 10, using the remainder as a decimal digit
// this will build a string with digits in reverse order, so
// before returning, it will be reversed to correct this.
do {
const auto next_bi = divide(bi, {10});
const char digit_value = static_cast<char>(bi.size() ? bi[0] : 0);
dec_string.push_back('0' + digit_value);
bi = next_bi;
} while(!is_zero(bi));
std::reverse(dec_string.begin(), dec_string.end());
return dec_string;
}
}
int main() {
bigint::BiType my_big_int = {453860625, 469837947, 3503557200, 40};
auto dec_string = bigint::get_decimal(my_big_int);
std::cout << dec_string << '\n';
}
Output:
3233755723588593872632005090577
I am currently using the code below that removes all digits equal to zero from an integer.
int removeZeros(int candid)
{
int output = 0;
string s(itoa(candid));
for (int i = s.size(); i != 0; --i)
{
if (s[i] != '0') output = output * 10 + atoi(s[i]);
}
return output;
}
The expected output for e.g. 102304 would be 1234.
Is there a more compact way of doing this by directly working on the integer, that is, not string representation? Is it actually going to be faster?
Here's a way to do it without strings and buffers.
I've only tested this with positive numbers. To make this work with negative numbers is an exercise left up to you.
int removeZeros(int x)
{
int result = 0;
int multiplier = 1;
while (x > 0)
{
int digit = x % 10;
if (digit != 0)
{
int val = digit * multiplier;
result += val;
multiplier *= 10;
}
x = x / 10;
}
return result;
}
For maintainability, I would suggest, don't work directly on the numeric value. You can express your requirements in a very straightforward way using string manipulations, and while it's true that it will likely perform slower than number manipulations, I expect either to be fast enough that you don't have to worry about the performance unless it's in an extremely tight loop.
int removeZeros(int n) {
auto s = std::to_string(n);
s.erase(std::remove(s.begin(), s.end(), '0'), s.end());
return std::stoi(s);
}
As a bonus, this simpler implementation handles negative numbers correctly. For zero, it throws std::invalid_argument, because removing all zeros from 0 doesn't produce a number.
You could try something like this:
template<typename T> T nozeros( T const & z )
{
return z==0 ? 0 : (z%10?10:1)*nozeros(z/10)+(z%10);
}
If you want to take your processing one step further you can do a nice tail recursion , no need for a helper function:
template<typename T> inline T pow10(T p, T res=1)
{
return p==0 ? res : pow10(--p,res*10);
}
template<typename T> T nozeros( T const & z , T const & r=0, T const & zp =0)
{
static int digit =-1;
return not ( z ^ r ) ? digit=-1, zp : nozeros(z/10,z%10, r ? r*pow10(++digit)+zp : zp);
}
Here is how this will work with input 32040
Ret, z, r, zp, digits
-,32040,0,0, -1
-,3204,0,0, -1
-,320,4,0,0, -1
-,32,0,4,4, 0
-,3,2,4, 0
-,0,3,24, 1
-,0,0,324, 2
324,-,-,-, -1
Integer calculations are always faster than actually transforming your integer to string, making comparisons on strings, and looking up strings to turn them back to integers.
The cool thing is that if you try to pass floats you get nice compile time errors.
I claim this to be slightly faster than other solutions as it makes less conditional evaluations which will make it behave better with CPU branch prediction.
int number = 9042100;
stringstream strm;
strm << number;
string str = strm.str();
str.erase(remove(str.begin(), str.end(), '0'), str.end());
number = atoi(str.c_str());
No string representation is used here. I can't say anything about the speed though.
int removezeroes(int candid)
{
int x, y = 0, n = 0;
// I did this to reverse the number as my next loop
// reverses the number while removing zeroes.
while (candid>0)
{
x = candid%10;
n = n *10 + x;
candid /=10;
}
candid = n;
while (candid>0)
{
x = candid%10;
if (x != 0)
y = y*10 + x;
candid /=10;
}
return y;
}
If C++11 is available, I do like this with lambda function:
int removeZeros(int candid){
std::string s=std::to_string(candid);
std::string output;
std::for_each(s.begin(), s.end(), [&](char& c){ if (c != '0') output += c;});
return std::stoi(output);
}
A fixed implementation of g24l recursive solution:
template<typename T> T nozeros(T const & z)
{
if (z == 0) return 0;
if (z % 10 == 0) return nozeros(z / 10);
else return (z % 10) + ( nozeros(z / 10) * 10);
}
MAJOR EDIT: Can someone please explain to me how to fix operator/ so that it will work properly? i realize that the shift is not always correct, such as for 10 / 3, which will cause infinite loops. so how do i fix that?
the entire code is at http://ideone.com/GhF0e
uint128_t operator/(uint128_t rhs){
// Save some calculations ///////////////////////
if (rhs == 0){
std::cout << "Error: division or modulus by zero" << std::endl;
exit(1);
}
if (rhs == 1)
return *this;
if (*this == rhs)
return uint128_t(1);
if ((*this == 0) | (*this < rhs))
return uint128_t(0, 0);
// //////////////////////////////////////////////
uint128_t copyn(*this), quotient = 0;
while (copyn >= rhs){
uint128_t copyd(rhs), temp(1);
// shift the divosr to match the highest bit
while (copyn > (copyd << 1)){
copyd <<= 1;
temp <<= 1;
}
copyn -= copyd;
quotient += temp;
}
return quotient;
}
is this correct?
uint128_t operator/(uint128_t rhs){
// Save some calculations ///////////////////////
if (rhs == 0){
std::cout << "Error: division or modulus by zero" << std::endl;
exit(1);
}
if (rhs == 1)
return *this;
if (*this == rhs)
return uint128_t(1);
if ((*this == 0) | (*this < rhs))
return uint128_t(0);
uint128_t copyd(rhs);
// Checks for divisors that are powers of two
uint8_t s = 0;
while ((copyd.LOWER & 1) == 0){
copyd >>= 1;
s++;
}
if (copyd == 1)
return *this >> s;
// //////////////////////////////////////////////
uint128_t copyn(*this), quotient = 0;
copyd = rhs;
uint8_t n_b = 255, d_b = 0;
while (copyd){
copyd >>= 1;
d_b++;// bit size of denomiator
}
copyd = rhs;
while (n_b > d_b){
// get the highest bit of dividend at current step
n_b = 0;
uint128_t copycopyn(copyn);
while (copycopyn){
copycopyn >>= 1;
n_b++;
}
uint8_t highest_bit = n_b - d_b - 1;
copyn -= copyd << highest_bit;
quotient += uint128_t(1) << highest_bit;
}
if (n_b == d_b)
quotient++;
return quotient;
}
it seems to be correct, except im somehow getting random large values when modding by 10, even though my mod function is just
uint128_t operator%(uint128_t rhs){
return *this - (rhs * (*this / rhs));
}
In the expression "copyn > (copyd << 1)", "copyd << 1" can overflow, leading to the infinite loop you're observing. I would suggest checking for the overflow, or making the check something more like "(copyn >> n) > copyd".
What about this:
int div; // Uninitialized variable.
What happens if all the test on the stream fail.
Then div could have any value. If it is 0 (or 1) then rhs will never reach 0.
If there were an infinite loop, you wouldn't even be able to output -1. -1 isn't as small as -123455, but you should try it. There is nothing wrong with operator << but there is something wrong with your assumption about operator /. There's something else wrong too, but I'm not sure if I should do your homework ^_^
I'm not sure if this is the problem, but it looks like:
stream << out;
return stream;
Is outside of the function, at class scope.
You probably want to get rid of one of the }s after else.
How to check if the binary representation of an integer is a palindrome?
Hopefully correct:
_Bool is_palindrome(unsigned n)
{
unsigned m = 0;
for(unsigned tmp = n; tmp; tmp >>= 1)
m = (m << 1) | (tmp & 1);
return m == n;
}
Since you haven't specified a language in which to do it, here's some C code (not the most efficient implementation, but it should illustrate the point):
/* flip n */
unsigned int flip(unsigned int n)
{
int i, newInt = 0;
for (i=0; i<WORDSIZE; ++i)
{
newInt += (n & 0x0001);
newInt <<= 1;
n >>= 1;
}
return newInt;
}
bool isPalindrome(int n)
{
int flipped = flip(n);
/* shift to remove trailing zeroes */
while (!(flipped & 0x0001))
flipped >>= 1;
return n == flipped;
}
EDIT fixed for your 10001 thing.
Create a 256 lines chart containing a char and it's bit reversed char.
given a 4 byte integer,
take the first char, look it on the chart, compare the answer to the last char of the integer.
if they differ it is not palindrome, if the are the same repeat with the middle chars.
if they differ it is not palindrome else it is.
Plenty of nice solutions here. Let me add one that is not the most efficient, but very readable, in my opinion:
/* Reverses the digits of num assuming the given base. */
uint64_t
reverse_base(uint64_t num, uint8_t base)
{
uint64_t rev = num % base;
for (; num /= base; rev = rev * base + num % base);
return rev;
}
/* Tells whether num is palindrome in the given base. */
bool
is_palindrome_base(uint64_t num, uint8_t base)
{
/* A palindrome is equal to its reverse. */
return num == reverse_base(num, base);
}
/* Tells whether num is a binary palindrome. */
bool
is_palindrome_bin(uint64_t num)
{
/* A binary palindrome is a palindrome in base 2. */
return is_palindrome_base(num, 2);
}
The following should be adaptable to any unsigned type. (Bit operations on signed types tend to be fraught with problems.)
bool test_pal(unsigned n)
{
unsigned t = 0;
for(unsigned bit = 1; bit && bit <= n; bit <<= 1)
t = (t << 1) | !!(n & bit);
return t == n;
}
int palidrome (int num)
{
int rev = 0;
num = number;
while (num != 0)
{
rev = (rev << 1) | (num & 1); num >> 1;
}
if (rev = number) return 1; else return 0;
}
I always have a palindrome function that works with Strings, that returns true if it is, false otherwise, e.g. in Java. The only thing I need to do is something like:
int number = 245;
String test = Integer.toString(number, 2);
if(isPalindrome(test)){
...
}
A generic version:
#include <iostream>
#include <limits>
using namespace std;
template <class T>
bool ispalindrome(T x) {
size_t f = 0, l = (CHAR_BIT * sizeof x) - 1;
// strip leading zeros
while (!(x & (1 << l))) l--;
for (; f != l; ++f, --l) {
bool left = (x & (1 << f)) > 0;
bool right = (x & (1 << l)) > 0;
//cout << left << '\n';
//cout << right << '\n';
if (left != right) break;
}
return f != l;
}
int main() {
cout << ispalindrome(17) << "\n";
}
I think the best approach is to start at the ends and work your way inward, i.e. compare the first bit and the last bit, the second bit and the second to last bit, etc, which will have O(N/2) where N is the size of the int. If at any point your pairs aren't the same, it isn't a palindrome.
bool IsPalindrome(int n) {
bool palindrome = true;
size_t len = sizeof(n) * 8;
for (int i = 0; i < len / 2; i++) {
bool left_bit = !!(n & (1 << len - i - 1));
bool right_bit = !!(n & (1 << i));
if (left_bit != right_bit) {
palindrome = false;
break;
}
}
return palindrome;
}
Sometimes it's good to report a failure too;
There are lots of great answers here about the obvious way to do it, by analyzing in some form or other the bit pattern. I got to wondering, though, if there were any mathematical solutions? Are there properties of palendromic numbers that we might take advantage of?
So I played with the math a little bit, but the answer should really have been obvious from the start. It's trivial to prove that all binary palindromic numbers must be either odd or zero. That's about as far as I was able to get with it.
A little research showed no such approach for decimal palindromes, so it's either a very difficult problem or not solvable via a formal system. It might be interesting to prove the latter...
public static bool IsPalindrome(int n) {
for (int i = 0; i < 16; i++) {
if (((n >> i) & 1) != ((n >> (31 - i)) & 1)) {
return false;
}
}
return true;
}
bool PaLInt (unsigned int i, unsigned int bits)
{
unsigned int t = i;
unsigned int x = 0;
while(i)
{
x = x << bits;
x = x | (i & ((1<<bits) - 1));
i = i >> bits;
}
return x == t;
}
Call PalInt(i,1) for binary pallindromes
Call PalInt(i,3) for Octal Palindromes
Call PalInt(i,4) for Hex Palindromes
I know that this question has been posted 2 years ago, but I have a better solution which doesn't depend on the word size and all,
int temp = 0;
int i = num;
while (1)
{ // let's say num is the number which has to be checked
if (i & 0x1)
{
temp = temp + 1;
}
i = i >> 1;
if (i) {
temp = temp << 1;
}
else
{
break;
}
}
return temp == num;
In JAVA there is an easy way if you understand basic binary airthmetic, here is the code:
public static void main(String []args){
Integer num=73;
String bin=getBinary(num);
String revBin=reverse(bin);
Integer revNum=getInteger(revBin);
System.out.println("Is Palindrome: "+((num^revNum)==0));
}
static String getBinary(int c){
return Integer.toBinaryString(c);
}
static Integer getInteger(String c){
return Integer.parseInt(c,2);
}
static String reverse(String c){
return new StringBuilder(c).reverse().toString();
}
#include <iostream>
#include <math.h>
using namespace std;
int main()
{
unsigned int n = 134217729;
unsigned int bits = floor(log(n)/log(2)+1);
cout<< "Number of bits:" << bits << endl;
unsigned int i=0;
bool isPal = true;
while(i<(bits/2))
{
if(((n & (unsigned int)pow(2,bits-i-1)) && (n & (unsigned int)pow(2,i)))
||
(!(n & (unsigned int)pow(2,bits-i-1)) && !(n & (unsigned int)pow(2,i))))
{
i++;
continue;
}
else
{
cout<<"Not a palindrome" << endl;
isPal = false;
break;
}
}
if(isPal)
cout<<"Number is binary palindrome" << endl;
}
The solution below works in python:
def CheckBinPal(b):
b=str(bin(b))
if b[2:]==b[:1:-1]:
return True
else:
return False
where b is the integer
If you're using Clang, you can make use of some __builtins.
bool binaryPalindrome(const uint32_t n) {
return n == __builtin_bitreverse32(n << __builtin_clz(n));
}
One thing to note is that __builtin_clz(0) is undefined so you'll need to check for zero. If you're compiling on ARM using Clang (next generation mac), then this makes use of the assembly instructions for reverse and clz (compiler explorer).
clz w8, w0
lsl w8, w0, w8
rbit w8, w8
cmp w8, w0
cset w0, eq
ret
x86 has instructions for clz (sort of) but not reversing. Still, Clang will emit the fastest code possible for reversing on the target architecture.
Javascript Solution
function isPalindrome(num) {
const binaryNum = num.toString(2);
console.log(binaryNum)
for(let i=0, j=binaryNum.length-1; i<=j; i++, j--) {
if(binaryNum[i]!==binaryNum[j]) return false;
}
return true;
}
console.log(isPalindrome(0))