How can I view a short's bit representation? - c++

If I have this as pointer to memory as a pointer to shorts:
unsigned short* ms = reinterpret_cast<unsigned short*>(_memory);
and I know the size of ms (number of this shorts), I would like to see running through all these shorts and their binary representation.
How can I access the bits of each short in C++?

To see the binary representation of any variable of type T, you can do something like this:
template <typename T>
void print_raw(const T & x)
{
const unsigned char * const p = reinterpret_cast<const unsigned char *>(&x);
for (std::size_t i = 0; i != sizeof(T); ++i)
{
if (i != 0) std::putchar(' ');
std::printf("%02X", p[i]);
}
}
You can plug this into your list of shorts.
(You could even replace printf by two lookups of index p[i] / 16 and p[i] % 16 in a suitable alphabet:
static const char alphabet = "01234567890ABCDEF";
std::putchar(alphabet[p[i] / 16]);
std::putchar(alphabet[p[i] % 16]);
Or replace it by a genuine binary printer:
void print_byte(unsigned char b)
{
for (std::size_t i = CHAR_BIT; i != 0; --i)
{
std::putchar(b & (1u << (i-1)) ? '1' : '0');
}
}
You can chain that into the previous loop instead of the two printf calls.)

cout << "\t" << dec << x << "\t\t Decimal" << endl;
cout << "\t" << oct << x << "\t\t Octal" << endl;
cout << "\t" << hex << x << "\t\t Hex" << endl;
cout << "\t" << bitset<MAX_BITS>(x) << endl;
try through bitset
EDIT(added code)
#include <iostream>
#include <bitset>
using namespace std;
int main( int argc, char* argv[] )
{
unsigned short _memory[] = {0x1000,0x0010,0x0001};
unsigned short* ms = reinterpret_cast<unsigned short*>(_memory);
for(unsigned short* iter = ms; iter != ms + 3/*number_of_shorts*/; ++iter )
{
bitset<16> bits(*iter);
cout << bits << endl;
for(size_t i = 0; i<16; i++)
{
cout << "Bit[" << i << "]=" << bits[i] << endl;
}
cout << endl;
}
}
or
#include <iostream>
#include <algorithm>
#include <bitset>
#include <iterator>
int main( int argc, char* argv[] )
{
unsigned short _memory[] = {0x1000,0x0010,0x0001};
unsigned short* ms = reinterpret_cast<unsigned short*>(_memory);
unsigned int num_of_ushorts = 3;//
std::copy(ms, ms+num_of_ushorts, ostream_iterator<bitset<16>>(cout, " "));
}

for (size_t i=0; i<N_SHORTS_IN_BUFFER; i++)
// perform bitwise ops
where N_SHORTS_IN_BUFFER is the number of shorts in memory.
The number of bits in a short is CHAR_BIT * sizeof(short).

If you are working under the assumption that an unsigned short has 16 bits, then you can retrieve each of them with bitwise operations:
for( unsigned short* iter = ms; iter != ms + num_of_ushorts; ++iter )
{
int bitN = ( *iter ) & ( 1 << N ); // get the N bit
}

As _memory points to a list of shorts your ms pointer can be used as an array.
unsigned short* ms = reinterpret_cast<unsigned short*>(_memory);
for (int i = 0; i < NUM_SHORTS_IN_MEM; i++)
cout << i << "th element\t" << ms[i] << endl;

Related

How can I output bit pattern of infinity and NaN in C++?(IEEE standard)

I'm reading Computer Systems: A Programmer’s Perspective, then I found the Special Values's definition and corresponding bit patterns.
Now, I wanna output their bits using C++. I use their macro to output bits, obviously is incorrect, because macro defined to Integer!
#define FP_NAN 0x0100
#define FP_NORMAL 0x0400
#define FP_INFINITE (FP_NAN | FP_NORMAL)
What should I do to correctly output bits in the image above? and, Why compiler defined those Integer macros rather than IEEE standard?
below is my code.
#include <iostream>
#include <cmath>
#include <bitset>
using namespace std;
union U {
float f;
int i;
};
int main() {
U u1, u2;
u1.f = FP_NAN;
u2.f = FP_INFINITE;
cout << bitset<32>(u1.i) << endl;
cout << bitset<32>(u2.i) << endl;
return 0;
}
output:
01000011100000000000000000000000
01000100101000000000000000000000
My computer environment:
win10
mingw64
I wrote a quick-and-dirty double bit-wise output program a while back. You could modify it to work for float.
It has ANSI escape sequences in it, which might not be suitable for your environment.
The key part is just using a byte memory pointer and examining the bit state directly, rather than trying to get std::bitset to play nice.
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
using std::cout;
using std::fpclassify;
using std::memcpy;
using std::nan;
using std::numeric_limits;
using std::reverse;
using std::setw;
using std::size_t;
using std::string;
using std::stringstream;
using std::uint32_t;
using std::uint64_t;
namespace {
uint32_t low32_from(double d) {
char const* p = reinterpret_cast<char const*>(&d);
uint32_t result;
memcpy(&result, p, sizeof result);
return result;
}
uint32_t high32_from(double d) {
char const* p = reinterpret_cast<char const*>(&d);
p += 4;
uint32_t result;
memcpy(&result, p, sizeof result);
return result;
}
string hexstr(uint32_t value) {
char hex[] = "0123456789ABCDEF";
unsigned char buffer[4];
memcpy(buffer, &value, sizeof buffer);
auto p = &buffer[0];
stringstream ss;
char const* sep = "";
for (size_t i = 0; i < sizeof buffer; ++i) {
ss << sep << hex[(*p >> 4) & 0xF] << hex[*p & 0xF];
sep = " ";
++p;
}
return ss.str();
}
string bits(uint64_t v, size_t len) {
string s;
int group = 0;
while (len--) {
if (group == 4) { s.push_back('\''); group = 0; }
s.push_back(v & 1 ? '1' : '0');
v >>= 1;
++group;
}
reverse(s.begin(), s.end());
return s;
}
string doublebits(double d) {
auto dx = fpclassify(d);
unsigned char buffer[8];
memcpy(buffer, &d, sizeof buffer);
stringstream ss;
uint64_t s = (buffer[7] >> 7) & 0x1;
uint64_t e = ((buffer[7] & 0x7FU) << 4) | ((buffer[6] >> 4) & 0xFU);
uint64_t f = buffer[6] & 0xFU;
f = (f << 8) + (buffer[5] & 0xFFU);
f = (f << 8) + (buffer[4] & 0xFFU);
f = (f << 8) + (buffer[3] & 0xFFU);
f = (f << 8) + (buffer[2] & 0xFFU);
f = (f << 8) + (buffer[1] & 0xFFU);
f = (f << 8) + (buffer[0] & 0xFFU);
ss << "sign:\033[0;32m" << bits(s, 1) << "\033[0m ";
if (s) ss << "(-) ";
else ss << "(+) ";
ss << "exp:\033[0;33m" << bits(e, 11) << "\033[0m ";
ss << "(" << setw(5) << (static_cast<int>(e) - 1023) << ") ";
ss << "frac:";
// 'i' for implied 1 bit, '.' for not applicable (so things align correctly).
if (dx == FP_NORMAL) ss << "\033[0;34mi";
else ss << "\033[0;37m.\033[34m";
ss << bits(f, 52) << "\033[0m";
if (dx == FP_INFINITE) ss << " \033[35mInfinite\033[0m";
else if (dx == FP_NAN) ss << " \033[35mNot-A-Number\033[0m";
else if (dx == FP_NORMAL) ss << " \033[35mNormal\033[0m";
else if (dx == FP_SUBNORMAL) ss << " \033[35mDenormalized\033[0m";
else if (dx == FP_ZERO) ss << " \033[35mZero\033[0m";
ss << " " << d;
return ss.str();
}
} // anon
int main() {
auto lo = low32_from(1111.2222);
auto hi = high32_from(1111.2222);
cout << hexstr(lo) << "\n";
cout << hexstr(hi) << "\n";
cout << doublebits(1111.2222) << "\n";
cout << doublebits(1.0) << "\n";
cout << doublebits(-1.0) << "\n";
cout << doublebits(+0.0) << "\n";
cout << doublebits(-0.0) << "\n";
cout << doublebits(numeric_limits<double>::infinity()) << "\n";
cout << doublebits(-numeric_limits<double>::infinity()) << "\n";
cout << doublebits(nan("")) << "\n";
double x = 1.0;
while (x > 0.0) {
cout << doublebits(x) << "\n";
x = x / 2.0;
}
}
There are multiple problems with your code.
Problem #1:
FP_NAN and FP_INFINITE are not constants representing return values of std::fpclassify, which returns classification of given floating point number.
Problem 2:
Accessing inactive union member, i.e. not the latest assigned to, is UB. Most robust, well-known way to inspect memory representation of an object is to memcpy it into char buffer.
Taking it into account, you can write your code in following way:
#include <bitset>
#include <cmath> // nanf
#include <cstring> // memcpy
#include <iostream>
#include <limits>
#include <ranges>
template <typename T> // Template, because reusability
void print_bits(const T& t)
{
char buffer[sizeof(T)];
std::memcpy(buffer, &t, sizeof(T));
for (char c: buffer | std::views::reverse) //Endianness
{
std::cout << std::bitset<8>(c);
}
}
int main()
{
const double nan = std::nanf("");
const double inf = std::numeric_limits<float>::infinity();
print_bits(nan);
std::cout << '\n';
print_bits(inf);
std::cout << '\n';
}
0111111111111000000000000000000000000000000000000000000000000000
0111111111110000000000000000000000000000000000000000000000000000
http://coliru.stacked-crooked.com/a/0d6c30067c9e7e6a

How do I convert long doubles to char arrays?

I am running a C++ program to sort strings as numbers.
I am saving strings in a char array vector but want to sort numbers as numbers so I am converting number strings into long doubles by calling "tonum()" then converting them back to strings when I am done by calling "tostring()". I am calling "numstr()" strictly for readability and debugging. I convert numbers 0 through 7 and the 6th number across for each value changes every time I run it. In my actual program, the first 5 numbers also seem to change. How do I get consistent results for a long double so that I can properly sort long doubles in char arrays?
#include<iostream>
std::string::size_type sz;
//___________________________________________________
std::string tonum(std::string str)
{
const int len = sizeof(long double);
std::string out = "0000000000000000";
union
{
long double dbl;
char array[len];
};
try
{
dbl = stold(str);
}
catch(std::exception &err)
{
dbl = 0;
}
for (int i = 0; i < len; i++)
{
std::cout << (int)array[i] << "\n";
out[len-i-1] = array[i];
}
return(out);
}
//___________________________________________________
std::string fromnum(std::string str)
{
const int len = sizeof(long double);
std::string out = "";
union
{
long double dbl;
char array[len];
};
for (int i = 0; i < len; i++)
{
array[len-i-1] = str[i];
}
out = std::to_string(dbl);
return(out);
}
//_____________________________________________________
std::string numstr(std::string str)
{
std::string out = fromnum(str) + ":";
for (int i = 0; i < str.length(); i++)
{
std::string look = std::to_string(str[i]);
int lookint = stold(look,&sz);
if (lookint < 0) lookint += 256;
std::string look2 = std::to_string(lookint);
out += look2 + " ";
}
return(out);
}
//_____________________________________________________
int main()
{
std::cout << numstr(tonum("0")) << "\n";
std::cout << numstr(tonum("1")) << "\n";
std::cout << numstr(tonum("2")) << "\n";
std::cout << numstr(tonum("3")) << "\n";
std::cout << numstr(tonum("4")) << "\n";
std::cout << numstr(tonum("5")) << "\n";
std::cout << numstr(tonum("6")) << "\n";
std::cout << numstr(tonum("7")) << "\n";
}
//_____________________________________________________

How to pass a pointer to vector of pointers?

This is a C++ version of a duplicate question. I know the pointers to vectors a bit much in the following, but I did this in order to duplicate a much larger project. The members of info_a are not properly printing from within print_b and I have been unable to properly pass the vector of pointers.
With what I have tried, the members of info_a are not properly printing from within print_b. The first element is fine, but the next two are not.
The structs and print_b are from a third-party api and I am trying to pass in what they are expecting.
Here's the working code ...
http://coliru.stacked-crooked.com/a/c3ad6af6da9409a5
Does anyone see where I am going wrong?
typedef struct {
uint16_t a1;
uint8_t a2;
uint8_t a3;
} info_a;
typedef struct {
uint16_t id;
unsigned int arr_sz;
info_a *arr;
} info_b;
void print_a(const info_a* a)
{
using namespace std;
cout <<
"a->a1 0x" << hex << setfill('0') << setw(4) << a->a1 << std::endl <<
"a->a2 0x" << hex << setfill('0') << setw(2) << a->a2 << std::endl <<
"a->a3 0x" << hex << setfill('0') << setw(2) << a->a3 << std::endl;
}
void print_b(const info_b* b)
{
using namespace std;
cout << "b->id 0x" << hex << setfill('0') << setw(4) << b->id << endl
<< "b->arr_sz " << hex << setfill('0') << setw(2) << b->arr_sz << endl;
for (unsigned int i = 0; i < b->arr_sz; ++i) {
const info_a *elem = &(b->arr[i]);
print_a(elem);
}
}
int main(int argc, char **argv)
{
std::shared_ptr<std::vector<std::shared_ptr<info_a>>> sp_info_a =
std::make_shared<std::vector<std::shared_ptr<info_a>>>();
std::shared_ptr<std::vector<std::shared_ptr<info_b>>> sp_info_b =
std::make_shared<std::vector<std::shared_ptr<info_b>>>();
int offset = 0;
for (uint16_t i = 1; i <= 1; ++i) {
for (uint16_t j = 1; j <= 3; ++j) {
std::shared_ptr<info_a> a_info =
std::make_shared<info_a>(info_a { j, 0x31, 0x32 } );
sp_info_a->push_back(a_info);
}
std::shared_ptr<info_b> b_info = std::make_shared<info_b>(
info_b {
static_cast<uint16_t>(i),
static_cast<unsigned int>(sp_info_a->size()),
(*sp_info_a)[offset].get()
});
sp_info_b->push_back(b_info);
print_b(b_info.get());
}
return 0;
}
It doesn't work because you interpret an array of std::shared_ptr<info_a> as an array of info_a. This will work:
int main(int argc, char **argv)
{
std::shared_ptr<std::vector<info_a>> sp_info_a =
std::make_shared<std::vector<info_a>>();
std::shared_ptr<std::vector<std::shared_ptr<info_b>>> sp_info_b =
std::make_shared<std::vector<std::shared_ptr<info_b>>>();
int offset = 0;
for (uint16_t i = 1; i <= 1; ++i) {
for (uint16_t j = 1; j <= 3; ++j) {
sp_info_a->push_back(info_a { j, 0x31, 0x32 });
}
std::shared_ptr<info_b> b_info = std::make_shared<info_b>(
info_b {
static_cast<uint16_t>(i),
static_cast<unsigned int>(sp_info_a->size()),
sp_info_a->data() + offset
});
sp_info_b->push_back(b_info);
print_b(b_info.get());
}
return 0;
}
I have been unable to properly pass the vector of pointers
This is the core of the problem. The C API you're calling does not expect a vector of pointers, it expects a vector of structs.
In particular, this bit ...
unsigned int arr_sz;
info_a *arr;
... expects to find arr_sz structs in memory, one after the other, starting from arr.
Your code allocates all structs separately, then stores the address of the first one in arr. The printing code then walks off the end of arr[0], expecting to find the next struct, but as you've allocated them separately, they're stored who knows where in memory.
In order to fix this, whatever you do, you must create the equivalent of a std::vector<info_a> (which you can then wrap an info_b around, as a sort of array view). This is what gives you the guarantee that the structs are actually adjacent in memory.

Why is this plain array implementation slower than the std::vector implementation performance?

Why is this plain array implementation slower than the std::vector implementation performance?
Due to some weired results I was seeing on something I'm working on, I decided to write a simplified test to compare std::vector vs plain array efficiency.
I have a struct which I implement in both ways,
1 using plain arrays (of different sizes)
typedef struct {
uint16_t index;
uint16_t nvals;
uint16_t vals[50];
double mean;
} a_segment_t;
2 using STL
typedef struct {
uint16_t index;
uint16_t nvals;
vector<uint16_t> vals;
uint32_t mean;
} b_segment_t;
The creation of this object in memory is not what I'm interested in (so I dont mind the push_back()), once this object is in memory it is used for an operation and that efficiency is what I'm analyzing. The vals are filled with some random data.
The operation goes through the vals stored in each segment, in this case a simple mean calculation. The test is as follows:
using namespace std;
#include <stdint.h>
#include <stdlib.h> // srand, rand
#include <time.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#define NSEGMENTS 100
#define MAX_NPXS 50
#define N 10000
// plain array approach
typedef struct {
uint16_t index;
uint16_t nvals;
uint16_t vals[MAX_NPXS];
double mean;
} a_segment_t;
uint16_t operation(uint16_t, a_segment_t*);
uint16_t print(uint16_t nsegments, a_segment_t* p_segments);
// stl vector approach
typedef struct {
uint16_t index;
uint16_t nvals;
vector<uint16_t> vals;
uint32_t mean;
} b_segment_t;
uint16_t operation(uint16_t, vector<b_segment_t>*);
uint16_t print(uint16_t nsegments, vector<b_segment_t>*);
void delta_time(struct timespec*, struct timespec*, struct timespec*);
uint16_t operation(uint16_t nsegments, a_segment_t* p_segments) {
// the operation (plain array approach)
uint64_t sum;
for( uint16_t nsegment = 0; nsegment < nsegments; ++nsegment ) {
sum = 0;
for(uint16_t nval = 0; nval < p_segments[nsegment].nvals; ++nval){
sum = sum + p_segments[nsegment].vals[nval];
}
p_segments[nsegment].mean = sum/p_segments[nsegment].nvals;
}
return nsegments;
}
uint16_t print(uint16_t nsegments, a_segment_t* p_segments) {
// print data (plain array approach)
for( uint16_t nsegment = 0; nsegment < nsegments; ++nsegment ) {
cout << "index : " << setfill('0') << setw(3) << p_segments[nsegment].index;
cout << "\tnval : " << setfill('0') << setw(3) << p_segments[nsegment].nvals;
cout << "\tvals : [";
for(uint16_t nval = 0; nval < p_segments[nsegment].nvals; ++nval){
cout << p_segments[nsegment].vals[nval] << ",";
}
cout << "\b]" << endl;
}
return nsegments;
}
uint16_t operation(uint16_t nsegments, vector<b_segment_t>* p_segments) {
// the operation (stl vector approach)
uint32_t sum;
for (vector<b_segment_t>::iterator p_segment = p_segments->begin(); p_segment<p_segments->end(); ++p_segment) {
sum = 0;
for (vector<uint16_t>::iterator p_val = (p_segment->vals).begin(); p_val<(p_segment->vals).end(); ++p_val) {
sum = sum + (*p_val);
}
p_segment->mean = sum/(p_segment->nvals);
}
return nsegments;
}
uint16_t print(uint16_t nsegments, vector<b_segment_t>* p_segments) {
// print data (stl vector approach)
for (vector<b_segment_t>::iterator p_segment = p_segments->begin(); p_segment<p_segments->end(); ++p_segment) {
cout << "index : " << setfill('0') << setw(3) << p_segment->index;
cout << "\tnval : " << setfill('0') << setw(3) << p_segment->nvals;
cout << "\tvals : [";
for (vector<uint16_t>::iterator p_val = (p_segment->vals).begin(); p_val<(p_segment->vals).end(); ++p_val) {
cout << *p_val << ",";
}
cout << "\b]" << endl;
}
return nsegments;
}
void delta_time(struct timespec* t1, struct timespec* t2, struct timespec* dt) {
if ((t2->tv_nsec - t1->tv_nsec) < 0) {
dt->tv_sec = t2->tv_sec - t1->tv_sec - 1;
dt->tv_nsec = t2->tv_nsec - t1->tv_nsec + 1000000000;
} else {
dt->tv_sec = t2->tv_sec - t1->tv_sec;
dt->tv_nsec = t2->tv_nsec - t1->tv_nsec;
}
return;
}
int main(int argc, char const *argv[]) {
uint16_t nsegments = NSEGMENTS;
uint16_t nsegment = 0;
uint16_t i = 0;
//create an populate the segments with dummy data (plain array approach)
a_segment_t* a_segments = new a_segment_t[nsegments];
for( nsegment = 0; nsegment < nsegments; ++nsegment ) {
a_segments[nsegment].index = nsegment;
srand(nsegment);
a_segments[nsegment].nvals = rand() % MAX_NPXS + 1;
for(uint16_t nval = 0; nval < a_segments[nsegment].nvals; ++nval){
a_segments[nsegment].vals[nval] = nval;
}
}
//create an populate the segments with dummy data (stl vector approach)
nsegment = 0;
vector<b_segment_t> b_segments(nsegments);
for (vector<b_segment_t>::iterator p_segment = b_segments.begin(); p_segment<b_segments.end(); ++p_segment) {
p_segment->index = nsegment;
srand(nsegment);
p_segment->nvals = rand() % MAX_NPXS + 1;
for(uint16_t nval = 0; nval < p_segment->nvals; ++nval){
p_segment->vals.push_back(nval);
}
nsegment++;
}
// print(nsegments, a_segments);
// cout << "===================================" << endl;
// print(nsegments, &b_segments);
// cout << "===================================" << endl;
// ======================= plain array timing measure ========================
struct timespec a_times[N];
for(i = 0; i < N; i++) {
nsegments = operation(nsegments, a_segments);
clock_gettime(CLOCK_REALTIME, &(a_times[i]));
}
// ===========================================================================
// ========================= vector timing measure ===========================
struct timespec b_times[N];
for(i = 0; i < N; i++) {
nsegments = operation(nsegments, &b_segments);
clock_gettime(CLOCK_REALTIME, &(b_times[i]));
}
// ===========================================================================
// =========================== timing console log ============================
struct timespec a_deltatime[N], a_elapsedtime[N], b_deltatime[N], b_elapsedtime[N];
cout << "\t\t plain array\t\t stl vector" << endl;
cout << "frame #\telapsedtime\tdeltatime\telapsedtime\tdeltatime" << endl;
for(i = 0; i < N-1; i=i+1000) {
delta_time(&(a_times[0]), &(a_times[i]), &(a_elapsedtime[i]));
delta_time(&(a_times[i]), &(a_times[i+1]), &(a_deltatime[i]));
delta_time(&(b_times[0]), &(b_times[i]), &(b_elapsedtime[i]));
delta_time(&(b_times[i]), &(b_times[i+1]), &(b_deltatime[i]));
cout << i << ",\t"
<< a_elapsedtime[i].tv_sec << "." << setfill('0') << setw(9) << a_elapsedtime[i].tv_nsec << ",\t"
<< a_deltatime[i].tv_sec << "." << setfill('0') << setw(9) << a_deltatime[i].tv_nsec << ",\t"
<< b_elapsedtime[i].tv_sec << "." << setfill('0') << setw(9) << b_elapsedtime[i].tv_nsec << ",\t"
<< b_deltatime[i].tv_sec << "." << setfill('0') << setw(9) << b_deltatime[i].tv_nsec << endl;
}
// ===========================================================================
}
An online version. Note: All of the tests were compiled with -O3
Can someone please point out why the plain array implementation is slower than the std::vector implementation?
Shouldn't the plain array implementation be faster?
What can I do to improve the speed of the plain array implementation?
The compiler will do a much better job of optimising code if you express algorithms in terms of iterators. One of the reasons is that it can make assumptions about the size and overflow characteristics of array indexes (which translate to indexed addressing with offset in machine code).
Refactoring to express both operation() and print() in terms of iterators (which can be pointers):
#include <stdint.h>
#include <stdlib.h> // srand, rand
#include <time.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <numeric>
using namespace std;
#define NSEGMENTS 100
#define MAX_NPXS 50
#define N 10000
// plain array approach
typedef struct {
uint16_t index;
uint16_t nvals;
uint16_t vals[MAX_NPXS];
double mean;
} a_segment_t;
// stl vector approach
typedef struct {
uint16_t index;
uint16_t nvals;
vector<uint16_t> vals;
uint32_t mean;
} b_segment_t;
void delta_time(struct timespec*, struct timespec*, struct timespec*);
template<class Iter>
uint16_t operation(Iter first, Iter last) {
auto result = std::uint16_t(std::distance(first, last));
// the operation (plain array approach)
for( ; first != last ; ++first ) {
auto sum = std::accumulate(std::begin(first->vals), std::begin(first->vals) + first->nvals, uint64_t(0), std::plus<>());
first->mean = sum / first->nvals;
}
return result;
}
template<class Iter>
uint16_t print(Iter first, Iter last) {
auto result = std::uint16_t(std::distance(first, last));
// print data (plain array approach)
for( ; first != last ; ++first ) {
cout << "index : " << setfill('0') << setw(3) << first->index;
cout << "\tnval : " << setfill('0') << setw(3) << first->nvals;
cout << "\tvals : [";
for_each(std::begin(first->vals), std::begin(first->vals) + first->nvals, [](const auto& val)
{
cout << val << ",";
});
cout << "\b]" << endl;
}
return result;
}
void delta_time(struct timespec* t1, struct timespec* t2, struct timespec* dt) {
if ((t2->tv_nsec - t1->tv_nsec) < 0) {
dt->tv_sec = t2->tv_sec - t1->tv_sec - 1;
dt->tv_nsec = t2->tv_nsec - t1->tv_nsec + 1000000000;
} else {
dt->tv_sec = t2->tv_sec - t1->tv_sec;
dt->tv_nsec = t2->tv_nsec - t1->tv_nsec;
}
return;
}
int main(int argc, char const *argv[]) {
uint16_t nsegments = NSEGMENTS;
uint16_t nsegment = 0;
uint16_t i = 0;
//create an populate the segments with dummy data (plain array approach)
a_segment_t* a_segments = new a_segment_t[nsegments];
for( nsegment = 0; nsegment < nsegments; ++nsegment ) {
a_segments[nsegment].index = nsegment;
srand(nsegment);
a_segments[nsegment].nvals = rand() % MAX_NPXS + 1;
for(uint16_t nval = 0; nval < a_segments[nsegment].nvals; ++nval){
a_segments[nsegment].vals[nval] = nval;
}
}
//create an populate the segments with dummy data (stl vector approach)
nsegment = 0;
vector<b_segment_t> b_segments(nsegments);
for (vector<b_segment_t>::iterator p_segment = b_segments.begin(); p_segment<b_segments.end(); ++p_segment) {
p_segment->index = nsegment;
srand(nsegment);
p_segment->nvals = rand() % MAX_NPXS + 1;
for(uint16_t nval = 0; nval < p_segment->nvals; ++nval){
p_segment->vals.push_back(nval);
}
nsegment++;
}
// print(a_segments, a_segments + nsegments);
// cout << "===================================" << endl;
// print(b_segments.begin(), b_segments.end());
// cout << "===================================" << endl;
// ======================= plain array timing measure ========================
struct timespec a_times[N];
for(i = 0; i < N; i++) {
nsegments = operation(a_segments, a_segments + nsegments);
clock_gettime(CLOCK_REALTIME, &(a_times[i]));
}
// ===========================================================================
// ========================= vector timing measure ===========================
struct timespec b_times[N];
for(i = 0; i < N; i++) {
nsegments = operation(b_segments.begin(), b_segments.begin() + nsegments);
clock_gettime(CLOCK_REALTIME, &(b_times[i]));
}
// ===========================================================================
// =========================== timing console log ============================
struct timespec a_deltatime[N], a_elapsedtime[N], b_deltatime[N], b_elapsedtime[N];
cout << "\t\t plain array\t\t stl vector" << endl;
cout << "frame #\telapsedtime\tdeltatime\telapsedtime\tdeltatime" << endl;
for(i = 0; i < N-1; i=i+1000) {
delta_time(&(a_times[0]), &(a_times[i]), &(a_elapsedtime[i]));
delta_time(&(a_times[i]), &(a_times[i+1]), &(a_deltatime[i]));
delta_time(&(b_times[0]), &(b_times[i]), &(b_elapsedtime[i]));
delta_time(&(b_times[i]), &(b_times[i+1]), &(b_deltatime[i]));
cout << i << ",\t"
<< a_elapsedtime[i].tv_sec << "." << setfill('0') << setw(9) << a_elapsedtime[i].tv_nsec << ",\t"
<< a_deltatime[i].tv_sec << "." << setfill('0') << setw(9) << a_deltatime[i].tv_nsec << ",\t"
<< b_elapsedtime[i].tv_sec << "." << setfill('0') << setw(9) << b_elapsedtime[i].tv_nsec << ",\t"
<< b_deltatime[i].tv_sec << "." << setfill('0') << setw(9) << b_deltatime[i].tv_nsec << endl;
}
// ===========================================================================
}
Yields expected results:
plain array stl vector
frame # elapsedtime deltatime elapsedtime deltatime
0, 0.000000000, 0.000002000, 0.000000000, 0.000002000
1000, 0.001533000, 0.000001000, 0.001551000, 0.000002000
2000, 0.003061000, 0.000002000, 0.003096000, 0.000002000
3000, 0.004589000, 0.000001000, 0.004771000, 0.000002000
4000, 0.006255000, 0.000001000, 0.006433000, 0.000002000
5000, 0.007785000, 0.000002000, 0.007975000, 0.000001000
6000, 0.009326000, 0.000002000, 0.009494000, 0.000001000
7000, 0.010893000, 0.000002000, 0.011012000, 0.000001000
8000, 0.012435000, 0.000002000, 0.012650000, 0.000002000
9000, 0.014024000, 0.000002000, 0.014273000, 0.000001000
The two versions aren't actually equivalent.
Firstly, your "array version" has mean as a double, and the "STL version" has mean as uint32_t. For the two functions to be remotely equivalent, the calculation of mean needs to be the same.
Second, your "array version" uses array subscripting, whereas the STL version increments and dereferences iterators. Since the compiler/optimiser will need to allow for more concerns (such as pointer aliasing) in the array version, it is probably unable to optimise performance as much.
Try turning your array version into something like;
uint16_t operation(uint16_t nsegments, a_segment_t* p_segments)
{
uint64_t sum;
for(a_segment *pseg = p_segments, *eseg = p_segments + nsegments; pseg < eseg; ++pseg)
{
sum = 0;
for(uint16_t *val = pseg->vals, *eval = pseg->vals + pseg->nvals; val < eval; ++val)
{
sum = sum + (*val);
}
p_seg->mean = sum/(pseg->nvals);
}
return nsegments;
}
This will (barring mistakes I've made in translating to this form - I haven' tested) give the same result, but will at least give the compiler a fighting chance of being able to apply the same type of performance optimisations to your "array version" as to the "STL version".
This sort of thing is one reason (of several) that the C++ standard algorithms work with iterators, rather than array indexing on containers like vector. The compiler has a better chance of optimising performance. Note that a pointer is a type of iterator.

strncat _emulations_ multiple calls ignore changed n?

For self-study, here there are my 2 version of strncat (one with pointer+offset notation and one array version):
// 08_38.cpp
#include <iostream>
#include <cstring>
char * strncatPtr(char * a, char * b, size_t n);
char * strncatArr(char * a, char * b, size_t n);
int main (void) {
char string1[20] = "foobarqwerty";
char string2[20] = "asd";
// strncat
std::cout << "-----------------------" << std::endl;
std::cout << "--------STRNCAT--------" << std::endl;
std::cout << "-----------------------" << std::endl;
std::cout << strncat(string2, string1, 6) << std::endl;
std::cout << strcpy(string2, "asd") << std::endl;
std::cout << strncatPtr(string2, string1, 4) << std::endl;
std::cout << strcpy(string2, "asd") << std::endl;
std::cout << strncatArr(string2, string1, 3) << std::endl;
std::cout << strcpy(string2, "asd") << std::endl;
return 0;
}
// ------------------------------------
char * strncatPtr(char * a, char * b, size_t n){
unsigned int i = 0;
// go to the end;
for(; *(a+i) != '\0'; i++);
// and start copying
for(unsigned int j = 0;
((*(a+i+j) = *(b+j)) != '\0') && (j < n-1);
j++);
return a;
}
char * strncatArr(char * a, char * b, size_t n){
unsigned int i = 0;
// go to the end;
for(; a[i] != '\0'; i++);
// and start copying
for(unsigned int j = 0;
((a[i+j] = b[j]) != '\0') && (j < n-1);
j++);
return a;
}
I don't get why when i test them it considers size = 6 for every function call
-----------------------
--------STRNCAT--------
-----------------------
asdfoobar
asd
asdfoobar
asd
asdfoobar
asd
but if i test them separately, by commenting 2 different calls each time, they works fine... could you please enlighten me?
If the number of chars copied is less then the length of the string being concatenated then you are not adding a null-terminator to indicate the end of the string.