Save number with high decimal
-
Thank you @SimonSchroeder . I have written a code that has the result of many decimal places and I need to use these generated numbers. I use eigen library in the written code and these numbers are supposed to be the input of one of the functions of this library.
The function works great when the numbers are integers or have small decimals, but when the decimal places of the numbers are very high, like the two numbers I mentioned, the function can not calculate the result well.
I also wrote the code in MATLAB and tested it and it works well, but in C ++ the result is not good!
-
Not that this is a Qt issue, but can you provide a small example that demonstrates a problem?
The two values you provided can be adequately represented in a C++ float or double as @SimonSchroeder points out. If you are passing them to Eigen functions with a matching signature then there should be no particular problem.
MATLAB's default 16 significant digits matches a double, although it may internally be using an arbitrary precision engine that avoids some issues with accuracy of representation.
-
Yes, the code is as follow:
#include <iostream> #include "Eigen/Dense" using namespace std; using namespace Eigen; int main(){ // 3x3 array double arr1[][3]={{-4.41454283058227e-08,-4.15360517928287e-18,-2.08705000000000e-31}, {1,0,0}, {0,1,0}}; MatrixXd array(3,3); for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ array(i,j)=arr1[i][j]; } } MatrixXcd eig = array.eigenvalues(); }The results shown in eig are incorrect and that's the problem.
-
What do you expect? You're using double values in the first place... As already said - you have to create the values directly with eigen to get the correct precision.
-
Can you provide an example to solve this problem?
-
Can you provide an example to solve this problem?
@SeyMohsenFls No, I don't use such libraries. But found an example for boost::multiprecission. You should ask at the eigen forum (or boost) - they know such stuff much better.
-
Yes, the code is as follow:
#include <iostream> #include "Eigen/Dense" using namespace std; using namespace Eigen; int main(){ // 3x3 array double arr1[][3]={{-4.41454283058227e-08,-4.15360517928287e-18,-2.08705000000000e-31}, {1,0,0}, {0,1,0}}; MatrixXd array(3,3); for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ array(i,j)=arr1[i][j]; } } MatrixXcd eig = array.eigenvalues(); }The results shown in eig are incorrect and that's the problem.
@SeyMohsenFls said in Save number with high decimal:
The results shown in eig are incorrect and that's the problem.
Can you show us the output from both your little program and also from your Matlab code?
-
Yes.
in MATLAB:>> A=[-4.41454283058227e-08,-4.15360517928287e-18,-2.08705000000000e-31;1 0 0; 0 1 0]; >> eig(A) ans = 1.0e-07 * -0.440511378824384 -0.000942401498110 -0.000000502735733and in C++:
(-4.41454283058e-08, 0.0) (1.10850979645e-08, 0.0) (-1.10850979645e-08, 0.0) -
A floating point representation of most decimal numbers will not be exact: this is a fundamental limitation of a fixed number of binary digits. Even so, your specific input example closest possible representation are equal to the same specified number of decimal significant digits. They are not precisely equal though, as you will see in the output below.
The default interpretation of numeric literals is as doubles and MatrixXd is a matrix of doubles, so this is not a gross type conversion problem on input (like treating them as single-precision floats and losing the precision).
This is what I put in and get:
// cout.precision(17); // cout << array << std::endl; -4.4145428305822701e-08 -4.1536051792828701e-18 -2.0870500000000001e-31 1 0 0 0 1 0 // cout << eig << std::endl; (-4.4145428305822701e-08,0) (1.1085097964543275e-08,0) (-1.1085097964543283e-08,0)Now, testing the resulting eigenvalues
// Cross checks MatrixXd identity(3,3); identity.setIdentity(); for (int i = 0; i < 3; ++i) { MatrixXd result = array - (real(eig(i)) * identity); double det = result.determinant(); cout << i << ": " << det << std::endl; } 0: 1.8336247094772579e-25 1: -6.8327370866854444e-24 2: -4.0163905414930213e-24So the values are tiny but not precisely zero as they would be in the ideal, unlimited precision world.
Octave, a MatLab work-alike, gives this result:
octave:1> output_precision(16) octave:2> A=[-4.41454283058227e-08,-4.15360517928287e-18,-2.08705000000000e-31;1 0 0; 0 1 0]; octave:3> eigvals = eig(A) eigvals = -4.405113788243840e-08 -9.424014981096368e-11 -5.027357330211182e-14 octave:4> det(A - eigvals(1) * eye(3)) ans = -7.375946750553847e-38 octave:5> det(A - eigvals(2) * eye(3)) ans = 1.191979506216298e-43 octave:6> det(A - eigvals(3) * eye(3)) ans = 0Its cross check values are not all precisely zero. I suspect MatLab's will not be either.
I am guessing that both MatLab and Octave use an algorithm for determining the eigenvalues that is not the same as the one in Eigen. Error propagation and iteration limits may simply explain the differences. Only an Eigen forum will help explain exactly and probably suggest ways to help the situation.
-
Can you provide an example to solve this problem?
Use a stable solver. Your matrix is quite close to singular. QR comes to mind, eigen already provides it out of the box.