I am a C++ noob.
What I am trying to do is sum the values of a vector of doubles (let's call it x) and ignore any values that are NaN. I tried to look this up, but I couldn't find anything specifically referencing what would happen if a vector contains any NaN values.
E.g.:
// let's say x = [1.0, 2.0, 3.0, nan, 4.0]
y = sum(x) // y should be equal to 10.0
Would the accumulate function work here? Or would it return NaN if x contains a NaN? Would a for loop work here with a condition to check for if the value is NaN (if yes, how do I check if NaN? In Python, the language I know best, this kind of check is not always straightforward).
std::isnan returns true if the passed floating point value is not a number. You have to add this check to all functions to avoid including NANs in your calculations. For example for sum:
constexpr auto sum(auto list) {
typename decltype(list)::value_type result = 0;
for (const auto& i : list) {
if (!std::isnan(i)) { // < - crucial check here
result += i;
}
}
return result;
}
Demo:
int main() {
auto list = std::array{ 1.0f, 2.0f, 3.0f, NAN };
std::cout << sum(list); //prints out 6
}
you could use std::accumulate with a custom summation operation.
const std::vector<double> myVector{1.0, 2.0, 3.0, std::nan("42"), 4.0};
auto nansum = [](const double a, const double b)
{
return a + (std::isnan(b) ? 0 : b);
}
auto mySum = std::accumulate(myVector.begin(), myVector.end(), 0.0, nansum);
Related
This question already has an answer here:
Floating-point arithmetic: why would order of addition matter?
(1 answer)
Closed last year.
I have two vectors of double. The value of the double is between -1000 and 1000.
Both vectors contain the same numbers, but the order is different.
For example
Vector1 = {0.1, 0.2, 0.3, 0.4};
Vector2 = {0.4, 0.2, 0.1, 0.3};
Is there a guarantee that the sum of Vector1 will be exactly equal to the sum of Vector2, assuming the sum is done via:
double Sum = 0;
for (double Val : Vector) Sum += Val;
I am worried about double imprecisions.
Is there a guarantee that the sum of Vector1 will be exactly equal to the sum of Vector2, assuming the sum is done via:
No, there is no such guarantee in the C++ language.
In fact, there is an indirect practical guarantee - assuming typical floating point implementation - that the results would be unequal. (But compilers have ways of disabling such guarantees, and of enabling unsafe floating point optimisations that may cause the sum to be equal).
The difference is likely to be very small with the given input, but it can be very large with other inputs.
No, they are not guaranteed to be the same. Here's a simple concrete example:
#include <stdio.h>
int main(void) {
double x = 504.4883585687764;
double y = 29.585946026264367;
double z = 2.91427392498775;
double lhs = x + (y + z);
double rhs = z + (y + x);
printf("LHS : %5.30g\n", lhs);
printf("RHS : %5.30g\n", rhs);
printf("Equal: %s\n", lhs == rhs ? "yes" : "no");
return 0;
};
When run, this produces:
LHS : 536.988578520028568163979798555
RHS : 536.988578520028454477142076939
Equal: no
Read this and in general something about floating points.
Note that if you adding value of different magnitude they will be rounded in different way if order is changed giving a bit different result.
I have a uniform 1D grid with value {0.1, 0.22, 0.35, 0.5, 0.78, 0.92}. These values are equally positioned from position 0 to 5 like following:
value 0.1 0.22 0.35 0.5 0.78 0.92
|_________|_________|_________|_________|_________|
position 0 1 2 3 4 5
Now I like to extract/interpolated value positioned, say, at 2.3, which should be
val(2.3) = val(2)*(3-2.3) + val(3)*(2.3-2)
= 0.35*0.7 + 0.5*0.3
= 0.3950
So how should I do it in a optimized way in C++? I am on Visual Studio 2017.
I can think of a binary search, but is any some std methods/or better way to do the job? Thanks.
You can get the integer part of the interpolation value and use that to index the two values you need to interpolate between. No need to use binary search as you are always know between which two values you interpolate. Only need to look out for indices that are outside of the values if that could ever happen.
This only works if the values are always mapped to integer indices starting with zero.
#include <cmath>
float get( const std::vector<float>& val, float p )
{
// let's assume p is always valid so it is good as index
const int a = static_cast<int>(p); // round down
const float t = p - a;
return std::lerp(val[a], val[a+1], t);
}
Edit:
std::lerp is a c++20 feature. If you use earlier versions you can use the following implementation which should be good enough:
float lerp(float a, float b, float t)
{
return a + (b - a) * t;
}
i have a container which stores double values from a source, and i need to find the location of numbers when it appears in a specific order/pattern.
vector<double> m = {-0.15,0.2,-0.2,-0.1,0.5,-0.15,-0.8,0.35,-0.2,-0.35......nth}
is there any way to find the location of numbers, if the appear in a order(in sequence) like:
m[x] = 0.1 to 0.5 //value of m[x] must between those two values
m[x+1] = 0.35 to 0.7 //anywhere between the range
m[x+2] = -0.1 to 0.1 // "
m[x+3] = 0.0 to.03 // "
std::search with a custom predicate.
Your pattern would contain ranges, and you need a custom binary predicate returning true if the LHS double lies in the RHS range.
Un-tested example:
using Range = std::pair<double,double>;
std::vector<Range> pattern {{0.1, 0.5}, {0.35, 0.7}, {-0.1, 0.1}, {0.0, 0.03}};
auto match = std::search(begin(m), end(m),
begin(pattern), end(pattern),
[](double d, Range r) {
return (r.first < d) && (d < r.second);
});
Add appropriate epsilon for your double comparisons, etc. etc.
I am implementing a lambda to row normalize a 2D vector in C++. Consider the simple case of a 3x3 matrix.
1 0 1
0 1 0
0 1 1
My normalization factor is the sum of non-zero entries in the row. Each entry is then divided by this normalization factor. For instance, row 1 has 2 non-zero entries summing up 2. Therefore, I divide each entry by 2. The row normalized vector is defined as follows:
1/2 0 1/2
0 1 0
0 1/2 1/2
The relevant normalization code is shown here(note MAX_SIZE = 3). There is a syntactical error in the lambda capture list.
for(int i = 0; i < MAX_SIZE ; i++)
{
transform(matrix[i].begin(),matrix[i].end(),matrix.begin(), [matrix[i].begin()](int x){
return distance(matrix[i].begin(),lower_bound(matrix[i].begin(),matrix[i].end(),x))});
}
Am I missing anything here?
A lambda capture list in C++ can only specify the names of values to capture, and matrix[i].begin() is not a name, it is a temporary value. You can either give it a name or you can make a variable for it in the enclosing scope. Much of the surrounding code is missing, so I invented a working version of the code for you to dissect:
#include <algorithm>
#include <cstdio>
template<int N>
void normalize(double (&mat)[N][N]) {
std::for_each(std::begin(mat), std::end(mat),
[](double (&row)[N]) {
double sum = std::accumulate(std::begin(row), std::end(row), 0.0);
std::transform(std::begin(row), std::end(row), std::begin(row),
[sum](double x) { return x / sum; });
});
}
template<int N>
void print(const double (&mat)[N][N]) {
std::for_each(std::begin(mat), std::end(mat),
[](const double (&row)[N]) {
std::for_each(std::begin(row), std::end(row),
[](double x) { std::printf(" %3.1f", x); });
std::putchar('\n');
});
}
int main() {
double mat[3][3] = {
{ 1, 0, 1 },
{ 0, 1, 0 },
{ 0, 1, 1 },
};
std::puts("Matrix:");
print(mat);
normalize(mat);
std::puts("Normalized:");
print(mat);
return 0;
}
Here is the output:
Matrix:
1.0 0.0 1.0
0.0 1.0 0.0
0.0 1.0 1.0
Normalized:
0.5 0.0 0.5
0.0 1.0 0.0
0.0 0.5 0.5
This code is a bit weird, as far as C++ code goes, because it uses lambdas for everything instead of loops (or mixing for loops with higher-order-functions). But you can see that by having a variable for each row (named row) we can make it very easy to loop over that row instead of specifying matrix[i] everywhere.
The weird syntax for array parameters double (&mat)[N][N] is to avoid pointer decay, which allows us to use begin() and end() in the function body (which don't work if the parameters decay to pointers).
I want to set a float value to 1.0 if one vector equals another, and 0.0 if the vectors are not equal
if( v1 == v2 ) floatVal = 1.0 ;
else floatVal = 0.0 ;
But wouldn't it be "faster" or an optimization just to set
floatVal = (v1 == v2) ;
But it doesn't work. You can't implicitly (or explicitly) convert float to bool? Is there a way to do this or do I have to use the if statement branch?
Didn't you try "float(bool)" function?
GLSLangSpec.Full.1.20.8.pdf section 5.4.1 says you can do all those conversions.
CuriousChettai's right. Just write:
floatVal = float(v1 == v2);
GLSL gives you a compile-error if you assign values with possible loss of precision. So you can do things like:
float f = 3; // works
int i = 3.0; // compiler-error
int j = int(3.0); // works