Question

Je suis en train d'écrire un programme où je dois supprimer des points en double stockés dans une matrice. Le problème est que quand il s'agit de vérifier si ces points sont dans la matrice, Matlab ne peut pas les reconnaître dans la matrice, bien qu'ils existent.

Dans le code suivant, la fonction intersections obtient les points d'intersection:

[points(:,1), points(:,2)] = intersections(...
    obj.modifiedVGVertices(1,:), obj.modifiedVGVertices(2,:), ...
    [vertex1(1) vertex2(1)], [vertex1(2) vertex2(2)]);

Le résultat:

>> points
points =
   12.0000   15.0000
   33.0000   24.0000
   33.0000   24.0000

>> vertex1
vertex1 =
    12
    15

>> vertex2    
vertex2 =
    33
    24

Deux points (vertex1 et vertex2) devraient être éliminés du résultat. Il doit être fait par les commandes ci-dessous:

points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);

Après avoir fait cela, nous avons ce résultat inattendu:

>> points
points =
   33.0000   24.0000

Le résultat doit être une matrice vide. Comme vous pouvez le voir, la première (ou seconde?) Paire de [33.0000 24.0000] a été éliminé, mais pas le second.

Alors j'ai vérifié ces deux expressions:

>> points(1) ~= vertex2(1)
ans =
     0
>> points(2) ~= vertex2(2)
ans =
     1   % <-- It means 24.0000 is not equal to 24.0000?

Quel est le problème?


De façon plus surprenante, j'ai fait un nouveau script qui n'a que ces commandes:

points = [12.0000   15.0000
          33.0000   24.0000
          33.0000   24.0000];

vertex1 = [12 ;  15];
vertex2 = [33 ;  24];

points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);

Le résultat comme prévu:

>> points
points =  
   Empty matrix: 0-by-2
Était-ce utile?

La solution

Le problème que vous rencontrez concerne la façon dont à virgule flottante numéros sont représentés sur un ordinateur. Une discussion plus détaillée des représentations à virgule flottante apparaît vers la fin de ma réponse (La section « représentation flottante point »). TL; DR Version: parce que les ordinateurs ont des quantités limitées de mémoire, le nombre ne peut être représenté avec une précision finie. Ainsi, la précision des nombres à virgule flottante est limité à un certain nombre de décimales (environ 16 chiffres significatifs pour valeurs à double précision , la valeur par défaut utilisé dans Matlab).

Actual par rapport affiché précision

Maintenant, pour répondre à l'exemple spécifique de la question ... tout 24.0000 et 24.0000 sont affiche de la même manière, il se trouve qu'ils diffèrent en fait par de très petites quantités décimales dans cette Cas. Vous ne voyez pas parce que Matlab n'affiche 4 chiffres significatifs par défaut , en gardant la affichage global propre et bien rangé. Si vous voulez voir la pleine précision, vous devez soit émettre la commande format long ou afficher une représentation hexadécimale du nombre:

>> pi
ans =
    3.1416
>> format long
>> pi
ans =
   3.141592653589793
>> num2hex(pi)
ans =
400921fb54442d18

valeurs initialisées en fonction des valeurs calculées

Comme il n'y a qu'un nombre fini de valeurs qui peuvent être représentés pour un nombre à virgule flottante, il est possible pour un calcul pour aboutir à une valeur qui se situe entre deux de ces représentations. Dans un tel cas, le résultat doit être arrondi à l'un d'eux. Cela introduit une petite . Cela signifie également que l'initialisation d'une valeur directement ou par un calcul peut donner des résultats légèrement différents. Par exemple, la valeur 0.1 n'a pas une exact représentation à virgule flottante (il obtient légèrement arrondi), et si vous vous retrouvez avec des résultats contre-intuitifs comme celui-ci en raison de la façon ronde erreurs off accumulent:

>> a=sum([0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]);  % Sum 10 0.1s
>> b=1;                                               % Initialize to 1
>> a == b
ans =
  logical
   0                % They are unequal!
>> num2hex(a)       % Let's check their hex representation to confirm
ans =
3fefffffffffffff
>> num2hex(b)
ans =
3ff0000000000000

Comment gérer correctement les comparaisons à virgule flottante

Etant donné que les valeurs à virgule flottante peuvent différer par de très petites quantités, des comparaisons doivent être effectuées en vérifiant que les valeurs se situent dans une certaine plage (à savoir la tolérance) les uns des autres, par opposition à exactement égales entre elles. Par exemple:

a = 24;
b = 24.000001;
tolerance = 0.001;
if abs(a-b) < tolerance, disp('Equal!'); end

affiche "l'égalité!".

Vous pouvez ensuite modifier votre code à quelque chose comme:

points = points((abs(points(:,1)-vertex1(1)) > tolerance) | ...
                (abs(points(:,2)-vertex1(2)) > tolerance),:)

représentation en virgule flottante

Un bon aperçu des nombres à virgule flottante (et plus précisément le norme IEEE 754 pour l'arithmétique à virgule flottante ) est Ce que tout informaticien doivent savoir au sujet flottant -Point arithmétique par David Goldberg.

Un nombre à virgule flottante binaire est en fait représentée par trois nombres entiers: un bit de signe s, une mantisse (ou coefficient / fraction) b, et un e d'exposant. Pour le format double précision à virgule flottante , chaque nombre est représenté par 64 bits établis dans la mémoire comme suit:

 ici

La valeur réelle peut être trouvé avec la formule suivante:

enter image description ici

Ce format permet de représentations numériques dans la plage 10 ^ ^ -308 à 10 308. Pour Matlab vous pouvez obtenir ces limites de realmin et realmax :

>> realmin
ans =
    2.225073858507201e-308
>> realmax
ans =
    1.797693134862316e+308

Comme il y a un nombre fini de bits utilisés pour représenter un nombre à virgule flottante, il n'y a que tant de nombres finis qui peuvent être représentés dans la plage donnée ci-dessus. Entraîneront souvent Computations une valeur qui ne correspond pas exactement à l'une de ces représentations finies, de sorte que les valeurs doivent être arrondies. Ces rel="noreferrer"> se mettent en évidence de différentes manières, comme nous le verrons dans les exemples ci-dessus.

Afin de mieux comprendre ces erreurs d'arrondi, il est utile de regarder la précision en virgule flottante par rapport fourni par la fonction

Autres conseils

Regardez cet article: Les Périls de à virgule flottante. Bien que ses exemples sont en Fortran, il a un sens pour pratiquement toutes les langues de programmation modernes, y compris Matlab. Votre problème (et solution pour elle) est décrite dans la section « Comparaisons sûres ».

type

format long g

Cette commande affichera la pleine valeur du nombre. Il est susceptible d'être quelque chose comme 24,00000021321! = 24,00000123124

Essayez d'écrire

  

0,1 + 0,1 + 0,1 == 0,3.

Attention: Vous pourriez être surpris du résultat

Peut-être que les deux chiffres sont vraiment 24,0 et 24,000000001 mais vous ne voyez pas toutes les décimales.

Consultez la Matlab fonction EPS .

Matlab utilise les mathématiques à virgule flottante jusqu'à 16 chiffres de précision (seulement 5 sont affichés).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top