I'm trying to use cxx-11's std::unique() to find
the unique elements in an array:
#include <iostream>
#include <algorithm>
#include <vector>
#include <typeinfo>
int main(){
const int n=11;
double x[n],a3[n],a1[n];
x[0]=-0.717778;
x[1]=-0.496843;
x[2]=-0.429063;
x[3]=-0.3596;
x[4]=-0.205607;
x[5]=0.0730536;
x[6]=0.138018;
x[7]=0.585526;
x[8]=2.40104;
x[9]=3.75268;
x[10]=4.55704;
a3[0]=0.790832;
a3[1]=0.569896;
a3[2]=0.502116;
a3[3]=0.432653;
a3[4]=0.343625;
a3[5]=0.512472;
a3[6]=0.56708;
a3[7]=1.01459;
a3[8]=2.32799;
a3[9]=3.67962;
a3[10]=4.48398;
std::cout.precision(10);
std::copy(a3,a3+n,a1);
for(int i=0;i<n;i++) a1[i]+=x[i];
std::sort(a1,a1+n);
for(int i=0;i<n;i++) std::cout << a1[i] << std::endl;
std::cout << "---" << std::endl;
int n_1=std::unique(a1,a1+n)-a1;
std::cout << "length of unique subvector " << n_1 << std::endl;
std::cout << "---" << std::endl;
for(int i=0;i<n_1;i++) std::cout << a1[i] << std::endl;
std::cout << "---" << std::endl;
}
but when I'm running this code (link to coliru)
it returns:
original array
0.073053
0.073053
0.073053
0.073054
0.138018
0.5855256
0.705098
1.600116
4.72903
7.4323
9.04102
---
length of unique subarray 10
---
unique array
0.073053
0.073053
0.073054
0.138018
0.5855256
0.705098
1.600116
4.72903
7.4323
9.04102
---
the unique array still contains a duplicate (and so is wrong)!
what am I doing wrong?
Let's try with a bit more precision, std::cout.precision(20):
0.073052999999999979064
0.073053000000000034575
0.073053999999999952308
0.13801800000000000179
0.58552559999999997942
0.70509800000000000253
1.6001160000000000938
4.7290299999999998448
7.4322999999999996845
9.0410199999999996123
Since most decimal fractions can't be represented exactly by a binary floating point format, slightly different rounding errors cause slightly different results.
In general, you can't expect the results of different floating point calculations to be exactly equal, even if the corresponding calculations applied to mathematical real numbers would be.
You could instead test for "almost equality", carefully choosing a tolerance that's appropriate for your numerical domain. unique allows you to specify your own predicate, instead of a simple equality test:
std::unique(a1,a1+n,[](double x, double y){return std::abs(x-y) < tolerance;});
How about:
int n_1 = std::unique(a1,a1+n,
[](float a, float b)
{
return std::fabs(a-b) < 10e-9;
}
) - a1;
?
Live demo link
Related
What is the correct way to determine if a number (in my case it is a value of power of two calculated by pow(2,n)) is within the limits of values that one variable type can take? I'm doing it like this: if(pow (2,128)>std::numeric_limits<float>::max()), but this is evaluated as true although it is expected that float's maximum value is 2^128 or something more. Is there any better way to do this comparison?
For these kinds of limit checking, you can move the terms around to stay within the limits of the type.
In this case, pow(2,n) == exp(ln(2)*n) mathematically, so, rearranging terms, you can use n > ln(maxval)/ln(2)
You can take the base 2 logarithm of the maximum limit for the type of variable and compare it to n. For example: if(n > std::log2(std::numeric_limits<float>::max()). You probably don't want n to be exactly on the limit though, since I think stuff like floating point error might cause some problems.
First of all can you answer what is the result of pow(2, 128)?
The real question is what is the type for this expression?
The second question is do you know how floating point numbers work?
Take a look on this code to give you a hints:
#include <cmath>
#include <iostream>
#include <limits>
template<class T>
void printInfo(const std::string& desc, T x)
{
std::cout << desc << ' ' << typeid(x).name() << ' ' << x << std::endl;
}
int main()
{
printInfo("A", std::pow(2, 128));
printInfo("B", std::pow(2.0f, 128));
printInfo("A", std::pow(2, 128.0f));
auto c = std::pow(2.0f, 128.0f);
printInfo("C", c);
std::cout << (c > std::numeric_limits<float>::max()) << std::endl;
std::cout << (c == std::numeric_limits<float>::infinity()) << std::endl;
return 0;
}
https://wandbox.org/permlink/bHdKqToDKdC0hSvW
I recommend review documentation of numeric_limits.
And analyze this code:
#include <cmath>
#include <iostream>
#include <limits>
template<class T>
void print2exp()
{
std::cout << typeid(T).name() << '\n';
std::cout << "Radix = " << std::numeric_limits<T>::radix << '\n';
auto maxExp = std::numeric_limits<T>::max_exponent;
std::cout << "Max exp = " << maxExp << '\n';
std::cout << "2^maxExp = " << std::pow(static_cast<T>(2), static_cast<T>(maxExp)) << '\n';
std::cout << "2^(maxExp - 1) = " << std::pow(static_cast<T>(2), static_cast<T>(maxExp - 1)) << '\n';
}
int main()
{
print2exp<float>();
print2exp<double>();
print2exp<long double>();
return 0;
}
https://wandbox.org/permlink/J0hACKUKvKlV8lYK
So proper approach to this is (assuming that radix is 2):
if (x < std::numeric_limits<T>::max_exponent) {
return std::pow(static_cast<T>(2), static_cast<T>(x));
} else {
throw invalid_argument("x is to big to be use as 2^x");
}
I was trying to generate some random doubles in C++ (MSVC, though that isn't too important to me—I just didn't have another compiler to test) and I noticed that my quick program never generated negative numbers:
#include <iostream>
#include <random>
#include <ctime>
int main() {
std::mt19937 generator(clock());
std::uniform_real_distribution<double>
rand_dbl(std::numeric_limits<double>::min(),
std::numeric_limits<double>::max());
std::cout << "Double Limits: (" << std::numeric_limits<double>::min()
<< "," << std::numeric_limits<double>::max() << ")"
<< std::endl << std::endl;
int total_neg = 0;
for (int i=0; i<100; i++) {
double d = rand_dbl(generator);
if (d<0) total_neg++;
std::cout << d << " ";
}
std::cout << std::endl << std::endl
<< "Total negative random double is: " << total_neg << std::endl;
return 0;
}
No matter how many numbers I have it generate, it never generates a negative one. I understand why most of the numbers generated are in the 10307 - 10308 range (which isn't exactly what I wanted), but not why the numbers are always positive. I tried a few different generators (default, mt19937, minstd_rand0) without any difference in this aspect.
Can anyone describe why this is the case?
You set it up that way with the limits that you provided. std::numeric_limits<double>::min() gives the smallest positive double, and you used that as the lower bound on the distribution.
std::numeric_limits<double>::min()
Will return DBL_MIN which is the smalles value closest to 0 a double can hold. If you want the largest negative value then you need to use
std::numeric_limits<double>::lowest()
Which will return -DBL_MAX which is the largest negative value a double can hold.
From cppreference:
For floating-point types with denormalization, min returns the minimum positive normalized value.
(emphasis mine)
So it's pretty normal you only get positive values.
Could you tell what is displayed by those lines?
std::cout << "Double Limits: (" << std::numeric_limits<double>::min()
<< "," << std::numeric_limits<double>::max() << ")"
<< std::endl << std::endl;
What I'm trying to achieve is to take the average of the numbers stored in the array and find the number which is closest to it.
My code compiles, but has an error just after starting. I think it's something to do with the memory handling (I don't feel confident with pointers, etc. yet)
Could some nice guy take a look at my code and tell me what's wrong with it? (don't be hard on me, I'm a beginner)
#include <iostream>
#include <cmath>
using namespace std;
double* aver(double* arr, size_t size, double& average);
int main()
{
double arr[] = {1,2,3,4,5,7};
size_t size = sizeof(arr)/sizeof(arr[0]);
double average = 0;
double* p = aver(arr,size,average);
cout << *p << " " << average << endl;
}
double* aver(double* arr, size_t size, double& average){
int i,j,sum;
double* m = 0;
int tmp[7];
for(i=0;i<size;i++)
sum += arr[i];
average = sum/size;
for(j=0;j<size;j++){
tmp[j] = arr[j] - average;
if(abs(tmp[j])>*m)
*m = tmp[j];
}
return m;
}
The following
double* m = 0;
sets m to the null pointer. Any attempt to dereference it will result in undefined behaviour.
Change the above to:
double m = 0;
and replace *m with m everywhere, also changing the function's return type to just double.
Finally, you don't need the tmp array.
1 What's wrong with your code? The use of pointers and the resulting beginner errors.
2 How to compute the average in C++? Roughly like this:
#include <iostream>
#include <iomanip>
#include <vector>
#include <numeric>
int main()
{
std::vector<double> arr = {1,2,3,4,5,7};
auto average = std::accumulate(std::begin(arr),std::end(arr),0.0) / arr.size();
std::cout << " average = " << std::setprecision(16) << average << std::endl;
}
(note: compile with option -std=c++11)
3 How to find the number closest to it (the average)? If your computer is IEEE compliant (most are but some compiler optimisations violate that), the result of any arithmetic is rounded to the closest representable number. So, nothing special needs to be done here. However, accumulation of numbers is subject to round-off error and hence loss of precision. This can be minimised by accumulating the numbers in descending order of their absolute value, though there exist pathological cases where the computed accumulation is still rather imprecise. Find out more on, say, wikipedia.
4 How to find the array value closest to it (the average)? One way is shown in Johan's answer. However, it unnecessarily alters the array by performing a partial sort. Better use std::min_element
(no need to std::transform):
auto comp = [average](double left, double right)
{ return std::abs(left-average) < std::abs(right-average); };
auto closest = std::min_element(std::begin(arr), std::end(arr), comp);
std::cout << " value closest to average was "
<< *closest << " at position "
<< (closest-std::begin(arr))
<< std::endl;
building on to the answer by Walter, adding the 'find value closest to average' part:
#include <iostream>
#include <vector>
#include <numeric>
#include <cmath>
#include <algorithm>
int main()
{
std::vector<double> arr = {1,2,3,4,5,7};
auto average = std::accumulate(std::begin(arr),std::end(arr),0.0) / arr.size();
std::cout << " average = " << average << std::endl;
auto comp = [average](double left,double right){
return std::abs(left-average)<std::abs(right-average); };
auto mini=std::min_element(std::begin(arr),std::end(arr),comp);
std::cout << "value closest to average was " << *mini <<std::endl;
}
Alternative (slower) implementation using transform (reduces the number of calls to fabs, but does a copy):
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
int main()
{
std::vector<double> arr = {1,2,3,4,5,7};
auto average = std::accumulate(std::begin(arr),std::end(arr),0.0) / arr.size();
std::cout << " average = " << average << std::endl;
auto pred=[average](double x){return std::abs(x-average);};
auto arrcpy = arr;
std::transform(std::begin(arr),std::end(arr),std::begin(arrcpy),pred);
auto result = std::min_element(std::begin(arrcpy),std::end(arrcpy));
std::cout << "value closest to average was: " << arr[result-std::begin(arrcpy)];
}
Using a standard algorithm is usually the right thing to do as it is more maintainable. In this case I did not find a way to use a standard algorithm as fast as this (about 30% faster than the first solution above with 10e7 elements and -O2):
std::pair<double,double> smallest(std::abs(average-arr[0]),arr[0]);
for(auto a: arr){
auto v=std::abs(average-a);
if(v<smallest.first){
smallest={v,a};
}
}
std::cout << "value closest to average was " << smallest.second <<std::endl;
std::accumulate is supposed to be able to take either three or four arguments. In the former case it's just when you want to add the numbers in a container; in the latter case it's when you want to first apply a function and then add them. I've written code that generates a vector of random doubles and then does some stuff to them: first it performs an x->x^2 transform using std::transform, then adds them up with std::accumulate, and lastly combines the two actions into one using the four-argument version of std::accumulate.
Everything works except for step 3. Looking at the example code to be found at http://www.cplusplus.com/reference/numeric/accumulate/, I can't see any reason why this shouldn't work, but I'm getting a "Too many arguments error" when compiling (I'm using XCode. For some reason it doesn't tell me the line number, but I've narrowed it down to the second usage of std::accumulate). Any insights?
#include <numeric>
#include <time.h>
#include <math.h>
using std::vector;
using std::cout;
using std::endl;
double square(double a) {
return a*a;
}
void problem_2_1() {
vector<double> original;
//GENERATE RANDOM VALUES
srand((int)time(NULL));//seed the rand function to time
for (int i=0; i<10; ++i) {
double rand_val = (rand() % 100)/10.0;
original.push_back(rand_val);
cout << rand_val << endl;
}
//USING TRANSFORM
vector<double> squared;
squared.resize(original.size());
std::transform(original.begin(), original.end(), squared.begin(), square);
for (int i=0; i<original.size(); ++i) {
std::cout << original[i] << '\t' << squared[i] << std::endl;
}
//USING ACCUMULATE
double squaredLength = std::accumulate(squared.begin(), squared.end(), 0.0);
double length = sqrt(squaredLength);
cout << "Magnitude of the vector is: " << length << endl;
//USING 4-VARIABLE ACCUMULATE
double alt_squaredLength = std::accumulate(original.begin(), original.end(), 0.0, square);
double alt_length = sqrt(alt_squaredLength);
cout << "Magnitude of the vector is: " << alt_length << endl;
}
The fourth argument to that std::accumulate overload needs to be a binary operator. Currently you are using a unary one.
std::accumulate performs a binary operation between successive elements in a container, hence the need for a binary operator. The fourth argument replaces the default binary operation, addition. It does not apply a unary operation and then perform addition. If you want to square the elements and then add them, you would need something like
double addSquare(double a, double b)
{
return a + b*b;
}
Then
double x = std::accumulate(original.begin(), original.end(), 0.0, addSquare);
I'm displaying a large number of doubles on the console, and I would like to know in advance how many decimal places std::cout will decide to display for a given double. This is basically so I can make it look pretty in the console.
e.g. (pseudo-code)
feild_width = find_maximum_display_precision_that_cout_will_use( whole_set_of_doubles );
...
// Every cout statement:
std::cout << std::setw( feild_width ) << double_from_the_set << std::endl;
I figure cout "guesses"? a good precision to display based on the double. For example, it seems to display
std::cout << sqrt(2) << std::endl;
as 1.41421, but also
std::cout << (sqrt(0.5)*sqrt(0.5) + sqrt(1.5)*sqrt(1.5)) << std::endl;
as 2 (rather than 2.000000000000?????? or 1.99999999?????). Well, maybe this calculates to exactly 2.0, but I don't think that sqrt(2) will calculate to exactly 1.41421, so std::cout has to make some decision about how many decimal places to display at some point, right?
Anyway possible to predict this to formulate a find_maximum_display_precision...() function?
What you need is the fixed iomanip.
http://www.cplusplus.com/reference/iostream/manipulators/fixed/
double d = 10/3;
std::cout << std::setprecision(5) << std::fixed << d << std::endl;
Sometimes C++ I/O bites. Making pretty output is one of those sometimes. The C printf family is easier to control, more understandable, more terse, and isn't plagued with those truly awful ios:: global variables. If you need to use C++ output for other reasons, you can always sprintf/snprintf to a string buffer and then print that using the << to stream operator. IMHO, If you don't need to use C++ output, don't. It is ugly and verbose.
In your question you are mixing precision and width, which are two different things.
Other answers concentrate on precision, but the given precision is the maximum, not a minimum of displayed digits. It does not pad trailing zeros, if not ios::fixed or ios::scientific is set.
Here is a solution to determine the number of characters used for output, including sign and powers of 10:
#include <string>
#include <sstream>
#include <vector>
size_t max_width(const std::vector<double>& v)
{
size_t max = 0;
for (size_t i = 0; i < v.size(); ++i)
{
std::ostringstream out;
// optional: set precision, width, etc. to the same as in std::cout
out << v[i];
size_t length = out.str().size();
if (length > max) max = length;
}
return max;
}
std::cout::precision(); use it to determine precision
example :
# include <iostream>
# include <iomanip>
int main (void)
{
double x = 3.1415927
std::cout << "Pi is " << std::setprecision(4) << x << std::endl;
return 1;
}
This would display:
Pi is 3.142
This link also includes explanation for std::cout::precision();
http://www.cplusplus.com/reference/iostream/ios_base/precision/