this should be the final part of my integer class, and it seems to be very easy, and yet, something is wrong. is this code correct for multiplication using 2 deques?
// 0x12345 = {0x01, 0x23, 0x45}
integer operator*(integer rhs){
// long multiplication
unsigned int zeros = 0;
std::deque <uint8_t> row;
std::deque <std::deque <uint8_t> > temp;
integer out = 0;
for(std::deque <uint8_t>::reverse_iterator i = value.rbegin(); i != value.rend(); i++){
row = std::deque <uint8_t>(zeros++, 0); // zeros on the right hand side
uint8_t carry = 0;
for(std::deque <uint8_t>::reverse_iterator j = rhs.value.rbegin(); j != rhs.value.rend(); j++){
uint16_t prod = (uint16_t(*i) * uint16_t(*j)) + carry;// multiply through
row.push_front((uint8_t) prod);
carry = prod >> 8;
}
if (carry != 0)
row.push_front(carry);
out += integer(row);
}
return out;
}
it is giving me 4931550625 ^ 2 -> 24248133972899962689. assuming that the operator+ is correct, which i seems to be, is there some other explanation of why this is wrong
edit: i updated the code according to wxffles, but i think i did it wrong, since im still getting 2424..., and for 0x25 * 0x25 im getting 89 (decimal)
edit2: the correct code is posted
I think you are missing the last carry. Do you not need:
row.push_front(carry);
just before you add the row to out?
Related
I am currently taking an online data structures course using C++ and I'm working on a personal project to help me better understand the basics. The project I'm working on is an implementation of a bigint class, a class that supports storing and calculation of arbitrary-precision integers using arrays and not vectors or strings. I am struggling with the implementation of the major arithmetic operators.
The numbers are stored in the array from least to most significant digit (201 would be stored as {1,0,2}) and the calculations are performed in this order as well.
I have found some material relating to this but the vast majority use vectors/strings and did not help me much. A couple of other resources, such as this and this did help, but did not work when I tried to implement them in my code. For example, this code to implement the addition operator does not work and I either get a bad_alloc exception or the answer is just way wrong, but I can't seem to figure out why or how to solve it and I've been at it for days now:
bigint& operator+(const bigint& lhs, const bigint& rhs){
bool minus_sign = rhs.is_negative();
size_t amt_used = 0; // to keep track of items in the array
// initial size and size of resulting array
// set initial size to the size of the larger array
// set result_size to ini size plus one in case of carry
size_t ini_size = lhs.get_digit_count() > rhs.get_digit_count() ?
lhs.get_digit_count() : rhs.get_digit_count();
const size_t INITIAL_SIZE = ini_size;
const size_t RESULT_SIZE = INITIAL_SIZE+1;
uint8_t temp[RESULT_SIZE], // temporary array
result_arr[RESULT_SIZE],
lhs_arr[INITIAL_SIZE], rhs_arr[INITIAL_SIZE]; // new arrays for lhs/rhs of the same size to avoid overflow if one is smaller
//assign corresponding values to the new arrays
for (size_t i = 0; i < lhs.get_digit_count(); i++){
lhs_arr[i] = lhs.get_digit(i);
}
for (size_t i = 0; i < rhs.get_digit_count(); i++){
rhs_arr[i] = rhs.get_digit(i);
}
// perform addition
int carry = 0; //carry variable
size_t j = 0;
for ( ; j < INITIAL_SIZE; j++){
uint8_t sum = lhs_arr[j] + rhs_arr[j] + carry;
if (sum > 9){
result_arr[j] = sum - 10;
carry = 1;
amt_used++;
}
else{
result_arr[j] = sum;
carry = 0;
amt_used++;
}
}
if (carry == 1){
result_arr[j] = 1;
amt_used++;
}
// flip the array to most sig to least sig, since the constructor performs a switch to least-most sig.
size_t decrement_index = amt_used - 1;
for (int i = 0; i < RESULT_SIZE; i++){
temp[i] = result_arr[decrement_index];
decrement_index--;
}
for (int i = 0; i < RESULT_SIZE; i++){
result_arr[i] = temp[i];
}
// create new bigint using the just-flipped array and return it
bigint result(result_arr, amt_used, minus_sign);
return result;
}
Here's the error I get: Thread 1: EXC_BAD_ACCESS (code=1, address=0x5)
Either that or I get a really large number when I'm just adding 8700 + 2100
There are several issues with this code.
The use of the VLA extension (for temp etc) is not standard C++. These stack based arrays are not initialized, so they will contain random data. When you fill these arrays with data, you are not assigning to every element. This results in the garbage results when, for example, the left number is shorter than the right (so that several elements of lhs_arr have garbage data in them). These bad values will then be used in the addition array. Using std::vector would be standard compliant and result in the vector elements all being initialized to something appropriate (like 0). This could be where your "really large number" comes from.
When you "flip the array", decrement_index can be negative if not all of the result slots were used. This could be a cause of you EXC_BAD_ACCESS crashes.
Returning a reference to a local variable results in Undefined Behavior, since that local will be destroyed when the function returns resulting in a dangling reference. This could be a cause of either of your stated problems.
Your handling of negative numbers is completely wrong, since you don't really handle them at all.
I wrote a method intToBytes() and an corresponding method to test this function. In VisualStudio-Debugger I can see that the value '2C' is the last entry of the vector. Moreover it seems that I have some problems finding the right option to compare the two arrays in my test method. Thanks for your help.
vector<unsigned char> intToBytes(int paramInt){
vector<unsigned char> arrayOfByte(4);
for (int i = 0; i < 4; i++){
arrayOfByte[3 - i] = (paramInt >> (i * 8));
}
return arrayOfByte;
}
int intToBytesTest(){
int test1 = 44;
vector<unsigned char> test1Vector = intToBytes(test1);
BYTE exp1[] = {0x2C , 0x00 , 0x00 , 0x00 };
BYTE act1[] = {test1Vector.at(0), test1Vector.at(1), test1Vector.at(2), test1Vector.at(3)};
if (exp1 != act1){
return 1;
}
return 0;
}
You can't compare two raw BYTE arrays using ==. You're actually comparing to see if they're the same array, not if the arrays are identical.
Instead you can use std::vector as it has an overload for == that compares two instances to see if they're identical.
I was trying out the bitset class in C++ and I tried this with the number 137 as an example:
So, I converted it to binary number which gave me 10001001. Now, I wanted to cut off the MSB and store the rest bits 0001001 in another bit instance called bitarray and I was expecting to see that in the bitarray but it wasn't giving the right value. what could have been the problem? I was just trying to split the MSB from the rest of the bits in the 137 binary representation...here is the code:
bitset<8> bitarray;
bitset<8> bitsetObject(num);
int val = bitsetObject.size();
for (int i = 0; i <= (val - 1); i++)
{
if (i == 6)
break;
else
bitarray[i] = bitsetObject[i + 1];
}
If anyone knows how I could easily slice from the second element to the last element in the bitsetObject array, let me know. Thanks..
If you're just trying to make a new bitset object with the most significant set bit reset, then consider the following:
template<std::size_t N>
std::bitset<N> strip_mssb(std::bitset<N> bitarray)
{
for (std::size_t i = bitarray.size(); i--;)
if (bitarray[i])
{
bitarray.reset(i);
break;
}
return bitarray;
}
Online demo.
You set bitarray[0] equal to bitsetObject[1], which is 0 (assuming num is really 137).
You seem to expect the least bit of bitarray to be equal to 1.
This function doesnt work correctly for some inputs, So What is the mistake ?
All Projects Codes here : link
ps: I am using input that "bits.size()%8" equal to zero
QByteArray bitsToBytes(QBitArray bits) {
QByteArray bytes;
bytes.resize(bits.count()/8);
// Convert from QBitArray to QByteArray
for(int b=0; b<bits.count(); ++b)
bytes[b/8] = ( bytes.at(b/8) | ((bits[b]?1:0)<<(b%8)));
return bytes;
}
Topro algorithm should be correct as a whole. But my concert is with the test bits[b]?1:0.
By default, operator[] ( int i ) return "the bit at index position i as a modifiable reference" while operator[] ( int i ) const return a boolean. If the first definition is chozen, you will test if a reference is true.
Try Topro algorithm with bits.testBit(b).
i think it's maybe the bits shall be left shifted (7 - (b % 8)) bits
I tried this and got the expected result.
QBitArray bits;
QByteArray bytes;
bits.resize(12);
bits.fill(true);
bits.setBit(2,false);
bytes.resize((bits.count() - 1) / 8 + 1);
for(int b=0; b<bits.count(); ++b)
bytes[b/8] = ( bytes.at(b/8) | ((bits[b]?1:0)<<(7-(b%8))));
for (int b=0;b<bytes.size();b++)
printf("%d\n",(quint8)bytes.at(b));
Consider the case, where (bits.count() % 8) != 0 , e.g. 9
Then bytes.resize(bits.count()/8); returns the wrong result.
As Topro suggested in a comment, you could use bytes.resize((bits.count() - 1) / 8 + 1)).
I was working on an encryption algorithm and I wonder how I can change the following code into something simpler and how to reverse this code.
typedef struct
{
unsigned low : 4;
unsigned high : 4;
} nibles;
static void crypt_enc(char *data, int size)
{
char last = 0;
//...
// Pass 2
for (i = 0; i < size; i++)
{
nibles *n = (nibles *)&data[i];
n->low = last;
last = n->high;
n->high = n->low;
}
((nibles *)&data[0])->low = last;
}
data is the input and the output for this code.
You are setting both nibbles of every byte to the same thing, because you set the high nibble to the same as the low nibble in the end. I'll assume this is a bug and that your intention was to shift all the nibbles in the data, carrying from one byte to the other, and rolling around. Id est, ABCDEF (nibbles order from low to high) would become FABCDE. Please correct me if I got that wrong.
The code should be something like:
static void crypt_enc(char *data, int size)
{
char last = 0;
//...
// Pass 2
for (i = 0; i < size; i++)
{
nibles *n = (nibles *)&data[i];
unsigned char old_low = n->low;
n->low = last;
last = n->high;
n->high = old_low;
}
((nibles *)&data[0])->low = last;
}
Is everything okay now? No. The cast to nibbles* is only well-defined if the alignment of nibbles is not stricter than the alignment of char. And that is not guaranteed (however, with a small change, GCC generates a type with the same alignment).
Personally, I'd avoid this issue altogether. Here's how I'd do it:
void set_low_nibble(char& c, unsigned char nibble) {
// assumes nibble has no bits set in the four higher bits)
unsigned char& b = reinterpret_cast<unsigned char&>(c);
b = (b & 0xF0) | nibble;
}
void set_high_nibble(char& c, unsigned char nibble) {
unsigned char& b = reinterpret_cast<unsigned char&>(c);
b = (b & 0x0F) | (nibble << 4);
}
unsigned char get_low_nibble(unsigned char c) {
return c & 0x0F;
}
unsigned char get_high_nibble(unsigned char c) {
return (c & 0xF0) >> 4;
}
static void crypt_enc(char *data, int size)
{
char last;
//...
// Pass 2
for (i = 0; i < size; ++i)
{
unsigned char old_low = get_low_nibble(data[i]);
set_low_nibble(data[i], last);
last = get_high_nibble(data[i]);
set_high_nibble(data[i], old_low);
}
set_low_nibble(data[0], last);
}
Doing the reverse amounts to changing "low" to "high" and vice-versa; rolling to the last nibble, not the first; and going through the data in the opposite direction:
for (i = size-1; i >= 0; --i)
{
unsigned char old_high = get_high_nibble(data[i]);
set_high_nibble(data[i], last);
last = get_low_nibble(data[i]);
set_low_nibble(data[i], old_high);
}
set_high_nibble(data[size-1], last);
If you want you can get rid of all the transfers to the temporary last. You just need to save the last nibble of all, and then shift the nibbles directly without the use of another variable:
last = get_high_nibble(data[size-1]);
for (i = size-1; i > 0; --i) // the last one needs special care
{
set_high_nibble(data[i], get_low_nibble(data[i]));
set_low_nibble(data[i], get_high_nibble(data[i-1]));
}
set_high_nibble(data[0], get_low_nibble(data[0]));
set_low_nibble(data[0], last);
It looks like you're just shifting each nibble one place and then taking the low nibble of the last byte and moving it to the beginning. Just do the reverse to decrypt (start at the end of data, move to the beginning)
As you are using bit fields, it is very unlikely that there will be a shift style method to move nibbles around. If this shifting is important to you, then I recommend you consider storing them in an unsigned integer of some sort. In that form, bit operations can be performed effectively.
Kevin's answer is right in what you are attempting to do. However, you've made an elementary mistake. The end result is that your whole array is filled with zeros instead of rotating nibbles.
To see why that is the case, I'd suggest you first implement a byte rotation ({a, b, c} -> {c, a, b}) the same way - which is by using a loop counter increasing from 0 to array size. See if you can do better by reducing transfers into the variable last.
Once you see how you can do that, you can simply apply the same logic to nibbles ({al:ah, bl:bh, cl:ch} -> {ch:al, ah:bl, bh:cl}). My representation here is incorrect if you think in terms of hex values. The hex value 0xXY is Y:X in my notation. If you think about how you've done the byte rotation, you can figure out how to save only one nibble, and simply transfer nibbles without actually moving them into last.
Reversing the code is impossible as the algorithm nukes the first byte entirely and discards the lower half of the rest.
On the first iteration of the for loop, the lower part of the first byte is set to zero.
n->low = last;
It's never saved off anywhere. It's simply gone.
// I think this is what you were trying for
last = ((nibbles *)&data[0])->low;
for (i = 0; i < size-1; i++)
{
nibbles *n = (nibbles *)&data[i];
nibbles *next = (nibbles *)&data[i+1];
n->low = n->high;
n->high = next->low;
}
((nibbles *)&data[size-1])->high = last;
To reverse it:
last = ((nibbles *)&data[size-1])->high;
for (i = size-1; i > 0; i--)
{
nibbles *n = (nibbles *)&data[i];
nibbles *prev = (nibbles *)&data[i-1];
n->high = n->low;
n->low = prev->high;
}
((nibbles *)&data[0])->low = last;
... unless I got high and low backwards.
But anyway, this is NOWHERE near the field of encryption. This is obfuscation at best. Security through obscurity is a terrible terrible practice and home-brew encryption get's people in trouble. If you're playing around, all the more power to you. But if you actually want something to be secure, please for the love of all your bytes use a well known and secure encryption scheme.