Eigen c++ cast double to long int? - c++

Quick question:
consider this (wrong) casting from a double to a long int:
Eigen::VectorXd Price = Map<VectorXd>(price, n);
double TickFactor = 1.0 / TickSize;
Eigen::VectorXi IntPrice = (Price * TickFactor).cast <long int> ();
which gives the following error (Eigen 3.3.5, g++ 7.3.0):
eigen/Eigen/src/Core/util/StaticAssert.h:33:40: error: static assertion failed: YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
Now, this compiles:
Eigen::VectorXi IntPrice = (Price * TickFactor).cast <int> ();
here is my question. Does the line above allows for values of (Price * TickFactor) that are larger than the upper limit on a short int? --whatever that is on the current system, say 33K.

This line
Eigen::VectorXi IntPrice = (Price * TickFactor).cast <int> ();
is essentially equivalent to
Eigen::VectorXi IntPrice(Price.size());
for(Eigen::Index i=0; i<Price.size(); ++i)
IntPrice[i] = static_cast<int>(Price[i] * TickFactor;
Unless on your system short int and int are the same, you are limited to the size of int (not short int), and the behavior for overflows is (I think) undefined.
If you want 64bit integers, do as ggael suggested:
typedef Eigen::Matrix<int64_t,Dynamic,1> VectorXi64;
VectorXi64 IntPrice = (Price * TickFactor).cast<int64_t>();

Related

C++ boost library to generate negative binomial random variables

I'm new to C++ and I'm using the boost library to generate random variables. I want to generate random variables from a negative binomial distribution.
The first parameter of boost::random::negative_binomial_distribution<int> freq_nb(r, p); has to be an integer. I want to expand that to a real value. Therefore I would like to use a poisson-gamma mixture, but I fail to.
Here's an excerpt from my code:
int nr_sim = 1000000;
double mean = 2.0;
double variance = 15.0;
double r = mean * mean / (variance - mean);
double p = mean / variance;
double beta = (1 - p) / p;
typedef boost::mt19937 RNGType;
RNGType rng(5);
boost::random::gamma_distribution<double> my_gamma(r, beta);
boost::random::poisson_distribution<int> my_poi(my_gamma(rng));
int simulated_mean = 0;
for (int i = 0; i < nr_sim; i++) {
simulated_mean += my_poi(rng);
}
double my_result = (double)simulated_mean / (double)nr_sim;
With my_result == 0.5 there is definitly something wrong. Is it my_poi(my_gamma(rng))? If so, what is the correct way to solve that problem?

MSVC - expression must have pointer-to-object type but it has type "float" on generic array?

MSVC on Visual Studio 2019 says "expression must have pointer-to-object type but it has type "float" on generic array" here:
void _stdcall sample::Eff_Render(PWAV32FS SourceBuffer, PWAV32FS DestBuffer, int Length)
{
float gain = _gain;
for (int ii = 0; ii < Length; ii++)
{
(*DestBuffer)[ii][0] = (*SourceBuffer)[ii][0] * gain;
(*DestBuffer)[ii][1] = (*SourceBuffer)[ii][1] * gain;
}
}
the problem seems here:
(*DestBuffer)[ii][0] = (*SourceBuffer)[ii][0] * gain;
(*DestBuffer)[ii][1] = (*SourceBuffer)[ii][1] * gain;
Not sure why:
typedef float TWAV32FS[2];
typedef TWAV32FS *PWAV32FS;
Some flag to be disabled? On gcc this kind of "cast" seems auto-manage by the compiler.
What's the correct way to manage this? (maybe I'm wrong on gcc and didn't know...)
Change this:
(*DestBuffer)[ii][0] = (*SourceBuffer)[ii][0] * gain;
(*DestBuffer)[ii][1] = (*SourceBuffer)[ii][1] * gain;
To this:
DestBuffer[ii][0] = (SourceBuffer[ii][0]) * gain;
DestBuffer[ii][1] = (SourceBuffer[ii][1]) * gain;
Explanation:
(I'm guessing you are doing audio processing of a stereo signal in floating point).
DestBuffer and SourceBuffer are both arrays of samples. Each sample is a pair of floats.
Each sample is referenced like this:
DestBuffer[ii]
Each individual channel on a sample is referenced like this:
DestBuffer[ii][0]
DestBuffer[ii][1]
The error you have with this syntax:
(*DestBuffer)[ii][0]
Is that *DestBuffer is really the same as DestBuffer[0], or the first sample in the array. So (*DestBuffer)[ii] is the same as DestBuffer[0][ii] which is not what you want anyway. But (*DestBuffer)[ii][0] is the same as DestBuffer[0][ii][0] - which triggers the compiler error because that third dimension does not exist.
Having done some audio processing code before - don't forget to clamp the result of your multiplication with gain as appropriate.
Due to these typedefs
typedef float TWAV32FS[2];
typedef TWAV32FS *PWAV32FS;
the typedef name PWAV32FS is equivalent to float ( * )[2].
So the parameters SourceBuffer and DestBuffer actually are declared like
float ( *SourceBuffer )[2], float ( * DestBuffer )[2]
Thus the for loop should be rewritten like
for (int ii = 0; ii < Length; ii++)
{
DestBuffer[ii][0] = SourceBuffer[ii][0] * gain;
DestBuffer[ii][1] = SourceBuffer[ii][1] * gain;
}

Why is my code throwing a SIGBUS error, even when I store variables in heap?

In the method plotThermalNoise() of the Antenna class, for some reason the for loop does not run. Initially, I used int for n and i, however I need to work with much larger numbers than int can hold. SO, now I'm using a long int for both. The program no longer works, however. I stepped through it with GDB, and it seems I'm getting a SIGBUS error. I tried using new so as to store both variables in heap, however the loop still doesn't run.
#define k 0.0000000000000000000000138064852 //Boltzmann's constant
class Antenna{
double _srate, _sdur, _res, _temp, _band;
public:
Antenna(double sampling_rate, double sample_duration, double resistance_ohms, double temperature_kelvin, double bandwidth_Hz){
_srate = sampling_rate; _sdur = sample_duration;
_res = resistance_ohms; _temp = temperature_kelvin;
_band = bandwidth_Hz;
}
void plotThermalNoise();
};
void Antenna::plotThermalNoise(){
//calculate RMS, mean of Gaussian
double RMS = sqrt(4 * _res * k * _temp * _band);
double V = sqrt((4 * k * _temp * _band) / _res);
long int n = _srate / _sdur;
double x[*n],y[*n];
gRandom->SetSeed(time(NULL));
for(long int i = 0; i < n; ++i){
x[i] = i;
y[i] = gRandom->Gaus(V,RMS);
}
TGraph gr = new TGraph(n,x,y);
gr->SetTitle("Thermal Noise Voltage vs Time Trace;Seconds;Volts");
gr->Draw();
}
void dataAquisitionSim(){
Antenna test(4000000000, 0.000001, 50, 90, 500);
test.plotThermalNoise();
}
long int n = _srate / _sdur;
double x[*n],y[*n];
This code will not compile. I assume your actual code is:
long int n = _srate / _sdur;
double x[n],y[n];
With the parameters you pass in: 4000000000 for _srate and 0.000001 for _sdur, n becomes 4,000,000,000 / 0.000,000,1 == 4,000,000,000,000,000.
You then attempt to allocate two double arrays of that size on stack. The total size of these arrays is 64 peta-bytes.
The largest super-computer currently in existence has "over 10PiB of memory". So you only need something mere 6 times larger than that.
it seems I'm getting a SIGBUS error.
As you should. Some back of the envelope calculations should help you realize that just because your code compiles doesn't mean it will run.
even when I store variables in heap?
Unless you actually have a computer with more than 64PiB of RAM, stack vs. heap is irrelevant -- you'll run out of either.

How to customize range of setRandom?

Eigen provides facilities to play with Matrices, and vectors (where one dimension is 1). I'm trying to develop a function which fills a vector (double *array) with random numbers made by setRandom.
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
Matrix<double, Dynamic, Dynamic, RowMajor>::Map(array, size, 1).setRandom();
return array;
}
The code above does that but random range is [-1:1] as per https://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html#title35.
How do I change range to i.e. [0:99]?
Answer and comments so far seems to suggest adding a loop to obtain the desired result, like:
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
Matrix<double, Dynamic, Dynamic, RowMajor>::Map(array, size, 1).setRandom();
for (int i = 0; i < size; ++i)
array[i] = (array[i]+1)*50;
return array;
}
Here is a complete, single line, solution:
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
ArrayXd::Map(array,size) = (ArrayXd::Random(size)+1.)*0.5*(max-min) + min;
return array;
}
I'm using Array instead of linear-algebra Vector or Matrix to enable addition with a scalar.
As suggested in the comments, you should probably just perform arithmetic to get your random values into the desired range (i.e. +1, then * 50). This is basically what would happen with a different requested range anyway.

How can you convert a std::bitset<64> to a double?

Is there a way to convert a std::bitset<64> to a double without using any external library (Boost, etc.)? I am using a bitset to represent a genome in a genetic algorithm and I need a way to convert a set of bits to a double.
The C++11 road:
union Converter { uint64_t i; double d; };
double convert(std::bitset<64> const& bs) {
Converter c;
c.i = bs.to_ullong();
return c.d;
}
EDIT: As noted in the comments, we can use char* aliasing as it is unspecified instead of being undefined.
double convert(std::bitset<64> const& bs) {
static_assert(sizeof(uint64_t) == sizeof(double), "Cannot use this!");
uint64_t const u = bs.to_ullong();
double d;
// Aliases to `char*` are explicitly allowed in the Standard (and only them)
char const* cu = reinterpret_cast<char const*>(&u);
char* cd = reinterpret_cast<char*>(&d);
// Copy the bitwise representation from u to d
memcpy(cd, cu, sizeof(u));
return d;
}
C++11 is still required for to_ullong.
Most people are trying to provide answers that let you treat the bit-vector as though it directly contained an encoded int or double.
I would advise you completely avoid that approach. While it does "work" for some definition of working, it introduces hamming cliffs all over the place. You usually want your encoding to arrange things so that if two decoded values are near to one another, then their encoded values are near to one another as well. It also forces you to use 64-bits of precision.
I would manage the conversion manually. Say you have three variables to encode, x, y, and z. Your domain expertise can be used to say, for example, that -5 <= x < 5, 0 <= y < 100, and 0 <= z < 1, where you need 8 bits of precision for x, 12 bits for y, and 10 bits for z. This gives you a total search space of only 30 bits. You can have a 30 bit string, treat the first 8 as encoding x, the next 12 as y, and the last 10 as z. You are also free to gray code each one to remove the hamming cliffs.
I've personally done the following in the past:
inline void binary_encoding::encode(const vector<double>& params)
{
unsigned int start=0;
for(unsigned int param=0; param<params.size(); ++param) {
// m_bpp[i] = number of bits in encoding of parameter i
unsigned int num_bits = m_bpp[param];
// map the double onto the appropriate integer range
// m_range[i] is a pair of (min, max) values for ith parameter
pair<double,double> prange=m_range[param];
double range=prange.second-prange.first;
double max_bit_val=pow(2.0,static_cast<double>(num_bits))-1;
int int_val=static_cast<int>((params[param]-prange.first)*max_bit_val/range+0.5);
// convert the integer to binary
vector<int> result(m_bpp[param]);
for(unsigned int b=0; b<num_bits; ++b) {
result[b]=int_val%2;
int_val/=2;
}
if(m_gray) {
for(unsigned int b=0; b<num_bits-1; ++b) {
result[b]=!(result[b]==result[b+1]);
}
}
// insert the bits into the correct spot in the encoding
copy(result.begin(),result.end(),m_genotype.begin()+start);
start+=num_bits;
}
}
inline void binary_encoding::decode()
{
unsigned int start = 0;
// for each parameter
for(unsigned int param=0; param<m_bpp.size(); param++) {
unsigned int num_bits = m_bpp[param];
unsigned int intval = 0;
if(m_gray) {
// convert from gray to binary
vector<int> binary(num_bits);
binary[num_bits-1] = m_genotype[start+num_bits-1];
intval = binary[num_bits-1];
for(int i=num_bits-2; i>=0; i--) {
binary[i] = !(binary[i+1] == m_genotype[start+i]);
intval += intval + binary[i];
}
}
else {
// convert from binary encoding to integer
for(int i=num_bits-1; i>=0; i--) {
intval += intval + m_genotype[start+i];
}
}
// convert from integer to double in the appropriate range
pair<double,double> prange = m_range[param];
double range = prange.second - prange.first;
double m = range / (pow(2.0,double(num_bits)) - 1.0);
// m_phenotype is a vector<double> containing all the decoded parameters
m_phenotype[param] = m * double(intval) + prange.first;
start += num_bits;
}
}
Note that for reasons that probably don't matter to you, I wasn't using bit vectors -- just ordinary vector<int> to encoding things. And of course, there's a bunch of stuff tied into this code that isn't shown here, but you can probably get the basic idea.
One other note, if you're doing GPU calculations or if you have a particular problem such that 64 bits are the appropriate size anyway, it may be worth the extra overhead to stuff everything into native words. Otherwise, I would guess that the overhead you add to the search process will probably overwhelm whatever benefits you get by faster encoding and decoding.
Edit:: I've decided that I was being a bit silly with this. While you do end up with a double it assumes that the bitset holds an integer... which is a big assumption to make. You will end up with a predictable and repeatable value per bitset but still I don't think that this is what the author intended.
Well if you iterate over the bit values and do
output_double += pow( 2, 64-(bit_position+1) ) * bit_value;
That would work. As long as it is big-endian