I am trying to copy n bits from any position of an array of uint8_ts into a single 64 bit integer. Here is a working solution that can copy an arbitrary amount of bits into a 64 bit integer starting at the beginning of the array, but I want to be able to start at any position of the array.
For example I might want to copy bits 2 through 11 of the array:
{7, 128, 7}
In binary that would be:
00000111 1000000 00000111
And I want an integer with value:
0001111000
std::uint64_t key_reg(std::uint8_t* bytes, std::size_t n)
{
std::uint64_t reg = 0;
// The amount of bits that fit into an entire element of an array
// ex, if I'm copying 17 bits, even_bytes == 2
std::size_t even_bytes = (n - (n % 8)) / 8;
// what's left over after the even bytes
// in this case, remainder == 1
std::size_t remainder = n - even_bytes * 8;
// copy each byte into the integer
for(std::size_t i = 0; i < even_bytes; ++i)
if(remainder)
reg |= (std::uint64_t)bytes[i] << (8 * (even_bytes - i));
else
reg |= (std::uint64_t)bytes[i] << (8 * (even_bytes - i - 1));
// if there is an uneven number of bits, copy them in
if(remainder)
reg |= (std::uint64_t)bytes[even_bytes];
return reg;
}
Do you have any idea how to implement
std::uint64_t key_reg(std::uint8_t* bytes, std::size_t pos, std::size_t n);
I didn't think anyone would answer so fast, so here was a solution I came up with in the same style. I found this bitfieldmask function on stackoverflow, but I'm unable to find the question to credit the author.
template<typename R>
static constexpr R bitfieldmask(unsigned int const a, unsigned int const b)
{
return ((static_cast<R>(-1) >> (((sizeof(R) * CHAR_BIT) - 1) - (b)))
& ~((1 << (a)) - 1));
}
std::uint64_t key_reg(std::uint8_t* bytes, std::size_t pos, std::size_t n)
{
std::uint64_t reg = 0;
std::size_t starting_byte = (pos < 8) ? 0 : ((pos - (pos % 8)) / 8);
std::size_t even_bytes = (n - (n % 8)) / 8;
std::size_t remainder = n - even_bytes * 8;
for(std::size_t i = 0; i < even_bytes; ++i)
if(remainder)
reg |= (std::uint64_t)bytes[starting_byte + i] << (8 * (even_bytes - i));
else
reg |= (std::uint64_t)bytes[starting_byte + i] << (8 * (even_bytes - i - 1));
if(remainder)
reg |= (std::uint64_t)bytes[even_bytes];
// mask out anything before the first bit
if(pos % 8 != 0) {
std::size_t a = n - pos;
std::size_t b = n;
auto mask = bitfieldmask<std::uint64_t>(a, b);
reg = (reg & ~mask);
}
return reg;
}
I think it is just simpler to copy all necessary bytes and then mask extra bits:
std::uint64_t key_reg(std::uint8_t* bytes, std::size_t n)
{
std::uint64_t reg = 0;
std::reverse_copy( bytes, bytes + n / 8 + ( n % 8 != 0 ),
reinterpret_cast<char *>( ® ) );
reg >>= n % 8;
reg &= ~( -1UL << n );
return reg;
}
using pos would be little more complex:
std::uint64_t key_reg(std::uint8_t* bytes, std::size_t pos, std::size_t n)
{
std::uint64_t reg = 0;
auto endpos = pos + n;
auto start = bytes + pos / 8;
auto end = bytes + endpos / 8 + ( endpos % 8 != 0 );
std::reverse_copy( start, end, reinterpret_cast<char *>( ® ) );
reg >>= endpos % 8;
reg &= ~( -1UL << n );
return reg;
}
live example
Your basic approach looks sound. To handle bit offsets that aren't multiples of 8, you just need to first read in a single partial byte and then proceed with the rest:
uint64_t key_reg(const uint8_t* bytes, size_t pos, size_t n) {
const uint8_t* ptr = bytes + pos / 8;
uint64_t result = 0;
if (pos % 8 > 0) {
/* read the first partial byte, masking off unwanted bits */
result = *(ptr++) & (0xFF >> (pos % 8));
if (n <= 8 - pos % 8) {
/* we need no more bits; shift off any excess and return early */
return result >> (8 - pos % 8 - n);
} else {
/* reduce the requested bit count by the number we got from this byte */
n -= 8 - pos % 8;
}
}
/* read and shift in as many whole bytes as we need */
while (n >= 8) {
result = (result << 8) + *(ptr++);
n -= 8;
}
/* finally read and shift in the last partial byte */
if (n > 0) {
result = (result << n) + (*ptr >> (8-n));
}
return result;
}
Here's an online demo with a simple test harness, demonstrating that this code indeed works correctly in all the edge cases I could find, such as reading a full 64 bits starting from the middle of a byte or reading only part of a single byte (which is actually a non-trivial special case, handled in a separate branch with its own return statement in the code above).
(Note that I wrote the code above in plain C since, like your original code, it doesn't really make use of any C++ specific features. Feel free to "C++ify" it by adding std:: where appropriate.)
One feature that the test harness doesn't check, but which I believe this code should possess, is that it never reads more bytes from the input array than necessary. In particular, the bytes array is not accessed at all if n == 0 (although a pointer to pos / 8 bytes after the start of the array is still calculated).
I have the following
struct MyType
{
std::array<uint8_t, 892> m_rguID;
uint16_t m_bitLength;
void GetBits(uint16_t startBit, uint16_t nBits, uint64_t & bits) const
};
void MyType::GetBits(uint16_t startBit, uint16_t nBits, uint64_t & bits) const
{
if(startBit + nBits > m_bitLength)
throw std::runtime_error("Index is out of range");
uint32_t num1 = startBit % 8U;
uint32_t num2 = 8U - num1;
uint32_t num3 = nBits >= num2 ? num2 : nBits;
uint32_t num4 = startBit >> 3;
bits = (uint64_t)(((int64_t)((uint64_t)m_rguID[num4] >> (8 - num3 - num1)) & (int64_t)((1 << num3) - 1)) << (nBits - num3));
uint32_t num5 = num4 + 1U;
int num6 = nBits - num3;
if(num6 <= 0)
return;
int num7 = num6 - 8;
int num8 = 8 - num6;
do
{
if(num6 >= 8)
{
bits |= (uint64_t)m_rguID[num5] << num7;
++num5;
}
else
{
bits |= (uint64_t)m_rguID[num5] >> num8;
++num5;
}
num6 += -8;
num7 += -8;
num8 += 8;
} while(num6 > 0);
}
Related
I have a lot of 32b values and I need to count the occurrence of each nth true bit over the entire length of the data and I need to do it as fast as possible because this is the performance bottleneck of the whole simulation. I created a naive c++ approach that does this for 8 bit values to illustrate the question:
#include <iostream>
#include <vector>
#include <cstdint>
std::vector<uint32_t> vertical_popcount(std::vector<uint8_t>& data) {
std::vector<uint32_t> result({0, 0, 0, 0, 0, 0, 0, 0});
for (auto i = 0; i < data.size(); i++) {
result[0] += (data[i] & 0b10000000) > 0;
result[1] += (data[i] & 0b01000000) > 0;
result[2] += (data[i] & 0b00100000) > 0;
result[3] += (data[i] & 0b00010000) > 0;
result[4] += (data[i] & 0b00001000) > 0;
result[5] += (data[i] & 0b00000100) > 0;
result[6] += (data[i] & 0b00000010) > 0;
result[7] += (data[i] & 0b00000001) > 0;
}
return result;
}
int main() {
std::vector<uint8_t> data({0b00000001, 0b00000100, 0b00000101});
auto result = vertical_popcount(data);
std::cout << "occurrence of bits: " << result[0] << ", " << result[1] << ", " << result[2] << ", " << result[3] << ", " << result[4] << ", " << result[5] << ", " << result[6] << ", " << result[7] << "\n";
return 0;
}
Is there an algorithm that does the same but (much) faster?
Pepijn Kramers answer shows how to parallelize the operations to do 8 byte at once. My answer looks at doing more bits at once.
In your code you extract each bit and increment a counter. You do a SIMD operation on that manually on blocks of 8 uint64_t.
The idea is to spread the bits out alternating 0 and data bits so that they can be added without overflowing into the next data bit. First step is to spread them out into 2bit units, then 4bit units, 8bit units and then sum the bytes in each uint64_t. If you want to extend this to 32 bit counts then you need to add 2 more steps to separate into 16bit units and 32bit units. The example below works on 8 uint64_t but if you have larger arrays you can merge more values per step. Just keep track of how many bits you have for each count (2, 4, 8, 16, 32) and don't merge more than 2^n-1 values.
uint64_t data[8] = 0x0123456789ABCDEF;
static const uint64_t mask0 = 0x5555555555555555;
static const uint64_t mask1 = 0x3333333333333333;
static const uint64_t mask2 = 0x0F0F0F0F0F0F0F0F;
// split even and odd bits and add 2 values together
// 2 bit per count, max value 2
uint64_t t000 = data[0] & mask0 + data[1] & mask0;
uint64_t t010 = data[2] & mask0 + data[3] & mask0;
uint64_t t020 = data[4] & mask0 + data[5] & mask0;
uint64_t t030 = data[6] & mask0 + data[7] & mask0;
uint64_t t001 = (data[0] >> 1) & mask0 + (data[1] >> 1) & mask0;
uint64_t t011 = (data[2] >> 1) & mask0 + (data[3] >> 1) & mask0;
uint64_t t021 = (data[4] >> 1) & mask0 + (data[5] >> 1) & mask0;
uint64_t t031 = (data[6] >> 1) & mask0 + (data[7] >> 1) & mask0;
// split into nibbles and build sum of 4 values
// 4 bit per count, max value 4
uint64_t t100 = t000 & mask1 + t010 & mask1;
uint64_t t101 = t001 & mask1 + t011 & mask1;
uint64_t t102 = (t000 >> 2) & mask1 + (t010 >> 2) & mask1;
uint64_t t103 = (t001 >> 2) & mask1 + (t011 >> 2) & mask1;
uint64_t t110 = t020 & mask1 + t030 & mask1;
uint64_t t111 = t021 & mask1 + t031 & mask1;
uint64_t t112 = (t020 >> 2) & mask1 + (t030 >> 2) & mask1;
uint64_t t113 = (t021 >> 2) & mask1 + (t031 >> 2) & mask1;
// split into bytes, and build sum of 8 values
// 8 bit per count, max 8
uint64_t sum[] = { t100 & mask2 + t110 & mask2;
t101 & mask2 + t111 & mask2;
t102 & mask2 + t112 & mask2;
t103 & mask2 + t113 & mask2;
(t100 >> 4) & mask2 + (t110 >> 4) & mask2;
(t101 >> 4) & mask2 + (t111 >> 4) & mask2;
(t102 >> 4) & mask2 + (t112 >> 4) & mask2;
(t103 >> 4) & mask2 + (t113 >> 4) & mask2; }
// add 8 bytes of sum[i] into a single byte
for(int i = 0; i < 8; ++i) {
sum[i] = sum[i] & 0xFFFFFFFF + (sum[i] >> 32);
sum[i] = sum[i] & 0xFFFF + (sum[i] >> 16);
sum[i] = sum[i] & 0xFF + (sum[i] >> 8);
}
Unless I made a mistake sum should now hold the bit count for each bit 0-7 for the block of 8 uint64_t.
You can improve this for larger blocks. When the bits are split into even and odd each count has 2 bits. That can hold the sum of 3 uint64_t and I only use 2. Similar the split into nibbles has 4 bits per count so it can hold the sum of 15 uint64_t. The split into bytes can hold the sum of 255 uint64_t.
You can also extend this to SIMD registers and do 128bit - 512bit at once. And I think there is a SIMD sum of bytes in vector intrinsic you can use instead of the loop at the end.
Here is a sketch of a possible approach (you can improve on this a lot if you can tweak your input to multiples of 8 bytes, or if you know the size of your vectors up front). But it gives you an idea how to use popcount. (For 32bits architecture the pattern is the same but you get less performance)
// #include <intrin.h> // for popcnt which counts number of set bits in a variable
#include <array>
#include <iostream>
#include <vector>
#include <cstdint>
#include <memory>
// work on copy on purpose so we can pad memory of vector to 64bit alignment (kind of a quick hack for now, the extra memory (re)allocations might slow you down too much)
auto vertical_popcount(std::vector<std::uint8_t> values)
{
// use 64bit architecture to do 8 values per cycle
static constexpr std::array<std::uint64_t, 8> masks
{
0x0101010101010101,
0x0202020202020202,
0x0404040404040404,
0x0808080808080808,
0x1010101010101010,
0x2020202020202020,
0x4040404040404040,
0x8080808080808080
};
//using an array instead of vector safes at least one dynamic allocation
std::array<std::size_t, 8> counts{};
// align data to multiple of 8 bytes
// add a few extra 0 bytes, they wont impact the counting
for (std::size_t n = 0; n < values.size() % 8; ++n)
values.push_back(0);
// make a uint64_t pointer into 8 bit data
// to pickup 8 bytes at a time for masking
auto ptr = reinterpret_cast<std::uint64_t*>(values.data());
for (std::size_t n = 0; n < values.size() / 8; ++n)
{
for (std::size_t m = 0; m < 8; ++m)
{
// mask 8 bytes at a time
auto masked_value = (*ptr & masks[m]);
// count bits of 8 uint8_t's in one loop
auto bitcount = std::popcount(masked_value);
counts[m] += bitcount;
}
++ptr;
}
return counts;
}
int main()
{
std::vector<uint8_t> data({ 0b00001001, 0b00000100, 0b00000101 });
auto result = vertical_popcount(data);
std::cout << "occurrence of bits: " << result[0] << ", " << result[1] << ", " << result[2] << ", " << result[3] << ", " << result[4] << ", " << result[5] << ", " << result[6] << ", " << result[7] << "\n";
return 0;
}
I am new to c++. I want to take input a unsigned 128 bit integer using scanf and print it using printf. As I am new to c++ , I only know these two methods for input output. Can someone help me out?
You could use boost, but this library set must be installed yourself:
#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
int main()
{
using namespace boost::multiprecision;
uint128_t v = 0;
std::cin >> v; // read
std::cout << v << std::endl; // write
return 0;
}
If you want to get along without boost, you can store the value into two uint64_t as such:
std::string input;
std::cin >> input;
uint64_t high = 0, low = 0, tmp;
for(char c : input)
{
high *= 10;
tmp = low * 10;
if(tmp / 10 != low)
{
high += ((low >> 32) * 10 + ((low & 0xf) * 10 >> 32)) >> 32;
}
low = tmp;
tmp = low + c - '0';
high += tmp < low;
low = tmp;
}
Printing then, however, gets more ugly:
std::vector<uint64_t> v;
while(high | low)
{
uint64_t const pow10 = 100000000;
uint64_t const mod = (((uint64_t)1 << 32) % pow10) * (((uint64_t)1 << 32) % pow10) % pow10;
tmp = high % pow10;
uint64_t temp = tmp * mod % pow10 + low % pow10;
v.push_back((tmp * mod + low) % pow10);
low = low / pow10 + tmp * 184467440737 + tmp * /*0*/9551616 / pow10 + (temp >= pow10);
high /= pow10;
}
std::vector<uint64_t>::reverse_iterator i = v.rbegin();
while(i != v.rend() && *i == 0)
{
++i;
}
if(i == v.rend())
{
std::cout << 0;
}
else
{
std::cout << *i << std::setfill('0');
for(++i; i != v.rend(); ++i)
{
std::cout << std::setw(8) << *i;
}
}
Above solution works up to (including)
340282366920938463463374516198409551615
= 0x ffff ffff ffff ffff ffff ad06 1410 beff
Above, there is an error.
Note: pow10 can be varied, then some other constants need to be adjusted, e. g. pow10 = 10:
low = low / pow10 + tmp * 1844674407370955161 + tmp * 6 / pow10 + (temp >= pow10);
and
std::cout << std::setw(1) << *i; // setw also can be dropped in this case
Increasing results in reducing the maximum number for which printing still works correctly, decreasing raises the maximum. With pow10 = 10, maximum is
340282366920938463463374607431768211425
= ffff ffff ffff ffff ffff ffff ffff ffe1
I don't know where the error for the very highest numbers comes from, yet, possibly some unconsidered overflow. Any suggestions appreciated, then I'll improve the algorithm. Until then, I'd reduce pow10 to 10 and introduce a special handling for the highest 30 failing numbers:
std::string const specialValues[0] = { /*...*/ };
if(high == 0xffffffffffffffff && low > 0xffffffffffffffe1)
{
std::cout << specialValues[low - 0xffffffffffffffe2];
}
else
{
/* ... */
}
So at least, we can handle all valid 128-bit values correctly.
You can try from_string_128_bits and to_string_128_bits with 128 bits unsigned integers in C :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
__uint128_t from_string_128_bits(const char *str) {
__uint128_t res = 0;
for (; *str; res = res * 10 + *str++ - '0');
return res;
}
static char *to_string_128_bits(__uint128_t num) {
__uint128_t mask = -1;
size_t a, b, c = 1, d;
char *s = malloc(2);
strcpy(s, "0");
for (mask -= mask / 2; mask; mask >>= 1) {
for (a = (num & mask) != 0, b = c; b;) {
d = ((s[--b] - '0') << 1) + a;
s[b] = "0123456789"[d % 10];
a = d / 10;
}
for (; a; s = realloc(s, ++c + 1), memmove(s + 1, s, c), *s = "0123456789"[a % 10], a /= 10);
}
return s;
}
int main(void) {
__uint128_t n = from_string_128_bits("10000000000000000000000000000000000001");
n *= 7;
char *s = to_string_128_bits(n);
puts(s);
free(s); // string must be freed
// print 70000000000000000000000000000000000007
}
I have std::bitset<32> word and I want to choose randomly and index (0-31) of some bit which is 1. How can I do that without loops and counters. Is there any std::algorithm suitable for that?
If it's easier I can convert the bitset to string or int and make it on the string or int.
Here's a first stab at it:
std::bitset<32> bitset{...};
std::mt19937 prng(std::time(nullptr));
std::uniform_int_distribution<std::size_t> dist{1, bitset.count()};
std::size_t p = 0;
for(std::size_t c = dist(prng); c; ++p)
c -= bitset[p];
// (p - 1) is now the index of the chosen bit.
It works by counting the set bits, doing the random pick c in that interval, then looking for the cth set bit.
If you have 32-bit (or even 64-bit) bitset, more efficient solution would be to convert to integer and then use bitwise operations on that integer to get random set bit.
Here is how you can convert your bitset to unsigned long:
std::bitset<32> word(0x1028);
unsigned long ulWord = word.to_ulong(); // ulWord == 0x1028
Then you can use “Select the bit position“ function from the Bit Twiddling Hacks page to select random set bit efficiently:
unsigned int bitcnt = word.count();
unsigned int randomSetBitIndex = 63-selectBit(ulWord, random() % bitcnt + 1);
unsigned long randomSetBit = 1 << randomSetBitIndex;
Here is the full code:
// Select random set bit from a bitset
#include <iostream>
#include <bitset>
#include <random>
using namespace std;
unsigned int selectBit(unsigned long long v, unsigned int r) {
// Source: https://graphics.stanford.edu/~seander/bithacks.html
// v - Input: value to find position with rank r.
// r - Input: bit's desired rank [1-64].
unsigned int s; // Output: Resulting position of bit with rank r [1-64]
uint64_t a, b, c, d; // Intermediate temporaries for bit count.
unsigned int t; // Bit count temporary.
// Do a normal parallel bit count for a 64-bit integer,
// but store all intermediate steps.
a = v - ((v >> 1) & ~0UL/3);
b = (a & ~0UL/5) + ((a >> 2) & ~0UL/5);
c = (b + (b >> 4)) & ~0UL/0x11;
d = (c + (c >> 8)) & ~0UL/0x101;
t = (d >> 32) + (d >> 48);
// Now do branchless select!
s = 64;
s -= ((t - r) & 256) >> 3; r -= (t & ((t - r) >> 8));
t = (d >> (s - 16)) & 0xff;
s -= ((t - r) & 256) >> 4; r -= (t & ((t - r) >> 8));
t = (c >> (s - 8)) & 0xf;
s -= ((t - r) & 256) >> 5; r -= (t & ((t - r) >> 8));
t = (b >> (s - 4)) & 0x7;
s -= ((t - r) & 256) >> 6; r -= (t & ((t - r) >> 8));
t = (a >> (s - 2)) & 0x3;
s -= ((t - r) & 256) >> 7; r -= (t & ((t - r) >> 8));
t = (v >> (s - 1)) & 0x1;
s -= ((t - r) & 256) >> 8;
return 64-s;
}
int main() {
// Input
std::bitset<32> word(0x1028);
// Initialize random number generator
std::random_device randDevice;
std::mt19937 random(randDevice());
// Select random bit
unsigned long ulWord = word.to_ulong();
unsigned int bitcnt = word.count();
unsigned int randomSetBitIndex = 63-selectBit(ulWord, random() % bitcnt + 1);
unsigned long randomSetBit = 1 << randomSetBitIndex;
// Output
cout << "0x" << std::hex << randomSetBit << endl; // either 0x8, 0x20 or 0x1000
return 0;
}
Run it on Ideone.
I want to be able to take a user given double and write out in the DEC 64 dpfp format (http://www.wsmr.army.mil/RCCsite/Documents/106%20Previous%20Versions/106-07/appendixO.pdf). Having trouble getting this to line up correctly, anyone have experience or have written conversion functions for DEC types?
This seems pretty straight forward, let me take a shot at it. Note that I don't have any way of testing this for correctness.
std::vector<unsigned char> ToDEC64Float(double d)
{
uint64_t dec_bits = 0ULL;
if (d != 0.0)
{
assert(sizeof(double) == sizeof(uint64_t));
uint64_t bits = *reinterpret_cast<uint64_t*>(&d);
uint64_t fraction = bits & 0x000fffffffffffffULL;
int exp = (int)((bits >> 52) & 0x7ff) - 1023;
bool sign = (bool)(bits & 0x8000000000000000ULL);
// convert the individual values for the new format
fraction <<= 3;
exp += 1 + 128;
if (exp > 255)
throw std::overflow_error("overflow");
if (exp < 0 || (exp == 0 && fraction != 0))
throw std::underflow_error("underflow");
dec_bits = (uint64_t)sign << 63 | (uint64_t)exp << 55 | fraction;
}
std::vector<unsigned char> result;
for (int i = 0; i < 64; i+=8)
result.push_back((unsigned char)((dec_bits >> i) & 0xff));
return result;
}
double static const DECBytesToDouble(uint64_t value)
{
//DEC Byte Conversion Constants
static const float MANTISSA_CONSTANT = 0.5;
static const int32_t EXPONENT_BIAS = 128;
uint8_t * byte_array = (uint8_t*)&value;
uint8_t first = byte_array[0];
uint8_t second = byte_array[1];
uint8_t third = byte_array[2];
uint8_t fourth = byte_array[3];
uint8_t fifth = byte_array[4];
uint8_t sixth = byte_array[5];
uint8_t seventh = byte_array[6];
uint8_t eighth = byte_array[7];
// |second |first|fourth|third|sixth|fifth|eighth|seventh|
// |s|exponent|mantissa |
bool sign = second & 0x80;
std::cout<<"(DECBytesToDouble) Sign: "<<sign<<std::endl;
int32_t exponent = ((second & 0x7F) << 1) + ((first >> 7) & 0x1);
std::cout<<"(DECBytesToDouble) Exponent: "<<exponent<<std::endl;
int64_t mantissa = ((int64_t)(first & 0x7F) << 48) + ((int64_t)fourth << 40)
+ ((int64_t)third << 32) + ((int64_t)sixth << 24) + ((int64_t)fifth << 16)
+ ((int64_t)eighth << 8) + (int64_t) seventh;
std::cout<<"(DECBytesToDouble) Fraction: "<<mantissa<<std::endl;
double fraction = MANTISSA_CONSTANT;
for (int32_t i=0; i<55; i++)
{
fraction += ((mantissa >> i) & 0x1) * pow(2,i-56);
}//for
return pow(-1,sign)*fraction*pow(2,exponent-EXPONENT_BIAS);
}//DECBytesToDouble
uint64_t static const DoubleToDECBytes(double value)
{
static const int32_t EXPONENT_BIAS = 128;
uint64_t dec_bits = 0ULL;
if (value != 0.0)
{
uint64_t bits = *reinterpret_cast<uint64_t*>(&value);
uint64_t fraction = bits & 0x000fffffffffffffULL;
int exp = (int)((bits >> 52) & 0x7ff) - 1023;
bool sign = false;
if(value < 0)
{
sign = true;
}//if
std::cout<<"(DoubleToDECBytes) Sign: "<<sign<<std::endl;
// convert the individual values for the new format
fraction <<= 3;
exp += EXPONENT_BIAS + 1;
std::cout<<"(DoubleToDECBytes) Exponent: "<<exp<<std::endl;
std::cout<<"(DoubleToDECBytes) Fraction: "<<fraction<<std::endl;
if (exp > 255)
throw std::overflow_error("overflow");
if (exp < 0 || (exp == 0 && fraction != 0))
throw std::underflow_error("underflow");
dec_bits = (uint64_t)(sign << 63) | (uint64_t)(exp << 55) | fraction;
//|second |first|fourth|third|sixth|fifth|eighth|seventh|
uint8_t * byte_array = (uint8_t*)&dec_bits;
uint8_t first = byte_array[0];
uint8_t second = byte_array[1];
uint8_t third = byte_array[2];
uint8_t fourth = byte_array[3];
uint8_t fifth = byte_array[4];
uint8_t sixth = byte_array[5];
uint8_t seventh = byte_array[6];
uint8_t eighth = byte_array[7];
byte_array[7] = second;
byte_array[6] = first;
byte_array[5] = fourth;
byte_array[4] = third;
byte_array[3] = sixth;
byte_array[2] = fifth;
byte_array[1] = eighth;
byte_array[0] = seventh;
std::cout<<"(DoubleToDECBytes) Guess ="<<dec_bits<<std::endl;
}//if
/*std::vector<unsigned char> result;
for (int i = 0; i < 64; i+=8)
{
result.push_back((unsigned char)((dec_bits >> i) & 0xff));
}//for
uint64_t final_result = 0;
memcpy(&final_result, &result[0], sizeof(uint64_t));
std::cout<<"Final result: "<<final_result<<std::endl;*/
return dec_bits;
}//DoubleToDECBytes
Output:
input uint64_t value: 9707381994276473045
(DECBytesToDouble) Sign: 0
(DECBytesToDouble) Exponent: 145
(DECBytesToDouble) Fraction: 24184718387676855
output double value: 109527.7465
(DoubleToDECBytes) Sign: 0
(DoubleToDECBytes) Exponent: 145
(DoubleToDECBytes) Fraction: 24184718387676848
(DoubleToDECBytes) Guess =9705411669439479893
Converted double, uint64_t: 9705411669439479893
uint64_t difference: 1970324836993152
(DECBytesToDouble) Sign: 0
(DECBytesToDouble) Exponent: 0
(DECBytesToDouble) Fraction: 24184718387676848
output double value: 0.0000
I came to find that integrating libvaxdata C library into my C++ solution was the best way to go. In my use case situation all that was required was some byte flipping, however the routines work flawlessly.
I recommend the libvaxdata library when dealing with conversion to/from IEEE/DEC types.
http://pubs.usgs.gov/of/2005/1424/
I'm working on a program in c++ to do md5 checksums. I'm doing this mainly because I think I'll learn a lot of different things about c++, checksums, OOP, and whatever else I run into.
I'm having trouble the check sums and I think the problem is in the function padbuff which does the message padding.
#include "HashMD5.h"
int leftrotate(int x, int y);
void padbuff(uchar * buffer);
//HashMD5 constructor
HashMD5::HashMD5()
{
Type = "md5";
Hash = "";
}
HashMD5::HashMD5(const char * hashfile)
{
Type = "md5";
std::ifstream filestr;
filestr.open(hashfile, std::fstream::in | std::fstream::binary);
if(filestr.fail())
{
std::cerr << "File " << hashfile << " was not opened.\n";
std::cerr << "Open failed with error ";
}
}
std::string HashMD5::GetType()
{
return this->Type;
}
std::string HashMD5::GetHash()
{
return this->Hash;
}
bool HashMD5::is_open()
{
return !((this->filestr).fail());
}
void HashMD5::CalcHash(unsigned int * hash)
{
unsigned int *r, *k;
int r2[4] = {0, 4, 9, 15};
int r3[4] = {0, 7, 12, 19};
int r4[4] = {0, 4, 9, 15};
uchar * buffer;
int bufLength = (2<<20)*8;
int f,g,a,b,c,d, temp;
int *head;
uint32_t maxint = 1<<31;
//Initialized states
unsigned int h[4]{ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
r = new unsigned int[64];
k = new unsigned int[64];
buffer = new uchar[bufLength];
if(r==NULL || k==NULL || buffer==NULL)
{
std::cerr << "One of the dyn alloc failed\n";
}
// r specifies the per-round shift amounts
for(int i = 0; i<16; i++)
r[i] = 7 + (5 * ((i)%4) );
for(int i = 16; i < 32; i++)
r[i] = 5 + r2[i%4];
for(int i = 32; i< 48; i++)
r[i] = 4 + r3[i%4];
for(int i = 48; i < 63; i++)
r[i] = 6 + r4[i%4];
for(int i = 0; i < 63; i++)
{
k[i] = floor( fabs( sin(i + 1)) * maxint);
}
while(!(this->filestr).eof())
{
//Read in 512 bits
(this->filestr).read((char *)buffer, bufLength-512);
padbuff(buffer);
//The 512 bits are now 16 32-bit ints
head = (int *)buffer;
for(int i = 0; i < 64; i++)
{
if(i >=0 && i <=15)
{
f = (b & c) | (~b & d);
g = i;
}
else if(i >= 16 && i <=31)
{
f = (d & b) | (~d & b);
g = (5*i +1) % 16;
}
else if(i >=32 && i<=47)
{
f = b ^ c ^ d;
g = (3*i + 5 ) % 16;
}
else
{
f = c ^ (b | ~d);
g = (7*i) % 16;
}
temp = d;
d = c;
c = b;
b = b + leftrotate((a + f + k[i] + head[g]), r[i]);
a = temp;
}
h[0] +=a;
h[1] +=b;
h[2] +=c;
h[3] +=d;
}
delete[] r;
delete[] k;
hash = h;
}
int leftrotate(int x, int y)
{
return(x<<y) | (x >> (32 -y));
}
void padbuff(uchar* buffer)
{
int lack;
int length = strlen((char *)buffer);
uint64_t mes_size = length % UINT64_MAX;
if((lack = (112 - (length % 128) ))>0)
{
*(buffer + length) = ('\0'+1 ) << 3;
memset((buffer + length + 1),0x0,lack);
memcpy((void*)(buffer+112),(void *)&mes_size, 64);
}
}
In my test program I run this on the an empty message. Thus length in padbuff is 0. Then when I do *(buffer + length) = ('\0'+1 ) << 3;, I'm trying to pad the message with a 1. In the Netbeans debugger I cast buffer as a uint64_t and it says buffer=8. I was trying to put a 1 bit in the most significant spot of buffer so my cast should have been UINT64_MAX. Its not, so I'm confused about how my padding code works. Can someone tell me what I'm doing and what I'm supposed to do in padbuff? Thanks, and I apologize for the long freaking question.
Just to be clear about what the padding is supposed to be doing, here is the padding excerpt from Wikipedia:
The message is padded so that its length is divisible by 512. The padding works as follows: first a single bit, 1, is appended to the end of the message. This is followed by as many zeros as are required to bring the length of the message up to 64 bits fewer than a multiple of 512. The remaining bits are filled up with 64 bits representing the length of the original message, modulo 264.
I'm mainly looking for help for padbuff, but since I'm trying to learn all comments are appreciated.
The first question is what you did:
length % UINT64_MAX doesn't make sense at all because length is in bytes and MAX is the value you can store in UINT64.
You thought that putting 1 bit in the most significant bit would give the maximum value. In fact, you need to put 1 in all bits to get it.
You shift 1 by 3. It's only half the length of the byte.
The byte pointed by buffer is the least significant in little endian. (I assume you have little endian since the debugger showed 8).
The second question how it should work.
I don't know what exactly padbuff should do but if you want to pad and get UINT64_MAX, you need something like this:
int length = strlen((char *)buffer);
int len_of_padding = sizeof(uint64_t) - length % sizeof(uint64_t);
if(len_of_padding > 0)
{
memset((void*)(buffer + length), 0xFF, len_of_padding);
}
You worked with the length of two uint64 values. May be you wanted to zero the next one:
uint64_t *after = (uint64_t*)(buffer + length + len_of_padding);
*after = 0;