La norme IEEE754 définit deux classes de NaN, la Nan tranquille, le QNAN et la Nan de signalisation, SNAN. Lorsqu'un SNAN est chargé dans un registre à point flottant, une exception est soulevée par l'unité à point flottant.
QNAN est disponible pour DelphI Code à travers la constante nommée J'aimerais pouvoir utiliser quelque chose de similaire pour déclarer une constante qui est une nan de signalisation, mais n'a pas encore trouvé de moyen de faire ça. p> naïvement, vous pouvez écrire ce code: p> mais l'ABI pour les valeurs de retour de point flottant signifie que le SNAN est chargé dans un point flottant inscrivez-vous pour que cela puisse être retourné. Naturellement, cela conduit à une exception qui défait plutôt le but. P> Vous êtes alors amené à écrire du code comme celui-ci: p> maintenant, cela fonctionne, Mais c'est très gênant. Supposons que vous ayez besoin de passer un SNAN à une autre fonction. Idéalement, vous souhaitez écrire: p> mais vous devez le faire: p> donc, après la construction -p, voici la question. p> existe-t-il un moyen d'écrire NAN code> qui est déclaré dans Math code>. La définition de cette constante est la suivante: p> x: = snan code> et avoir la variable de point flottant x code> attribué une valeur qui est attribuée une nan de signalisation? p> p>
5 Réponses :
Vous pouvez aligner la fonction: mais cela dépendra de l'ambiance d'optimisation et du compilateur. P> J'ai vu certaines fonctions non définies, sans aucune clair compréhension du contexte. Je n'aime pas ne pas s'appuyer sur l'inlinisation. P> Qu'est-ce que je ferais mieux de faire et qui fonctionnera sur toutes les versions de Delphi, est d'utiliser une variable globale: p> backup := Set8087CW($133F);
try
..
finally
Set8087CW(backup);
end;
Élever l'exception l'exception dans l'ensemble des nan de signalisation?
Dans mon expérience, si la fonction est définie à la section Démarrage b> de la section de mise en œuvre de l'unité compilée d'abord b>, la fonction sera toujours inlinée.
En ce qui concerne les tests de SNAN, il existe plusieurs modèles de bits SNAN. Donc, vous avez besoin d'un meilleur test. La fonction ISNAN en mathématiques est un bon point de départ.
@DavidHeffernan Mais je suppose que vous souhaitez principalement tester si la valeur SNAN a été définie par votre propre code, non? Dans ce cas, le test du motif bit SNAN64 est suffisant dans la pratique. Je voulais répondre à votre question, pas toutes les entreprises. :) Mais +1 sur votre commentaire.
@Uweraabe levant l'exception ... mais dans le cadre de la fonction, en ce qui concerne la question de la question. Vous ne pouvez pas me blâmer, car j'ai apporté la portée d'exception explicite et a donné une solution de contournement. C'est pourquoi j'ai ajouté des détails sur le registre de l'exception X87.
@Arnaudbouchez avez raison, en vrai code, il s'agira toujours de votre modèle de bit spécifique que vous testez. Et +1 pour la réponse.
Voici une autre solution de contournement:
type
ISet8087CW = interface
end;
TISet8087CW = class(TInterfacedObject, ISet8087CW)
protected
OldCW: Word;
public
constructor Create(const NewCW: Word);
destructor Destroy; override;
end;
TIEEE754 = record
case Byte of
0: (SNaN: Double);
1: (i: Int64);
end;
const
IEEE754: TIEEE754 = ( i: $7FF7FFFFFFFFFFFF);
{ TISet8087CW }
constructor TISet8087CW.Create(const NewCW: Word);
begin
OldCW := Get8087CW;
Set8087CW(NewCW);
inherited Create;
end;
destructor TISet8087CW.Destroy;
begin
Set8087CW(OldCW);
inherited;
end;
procedure TForm6.Button4Click(Sender: TObject);
var
CW: ISet8087CW;
begin
CW := TISet8087CW.Create($133F);
Memo1.Lines.Add(Format('SNaN: %f', [IEEE754.SNaN]));
end;
On dirait que le motif Raii est en train de décoller dans la terre de Delphes. ;-)
+1 J'aime assez la variante. En passant, saviez-vous que set8087cw code> n'est pas threadsafe?
@Warrenp: D J'aime cette approche ici, mais aussi quand, par exemple, montrant un curseur de sablier. Tout ce qui se passe (exception, etc.), dès que l'interface manque de portée, nous allons revenir au réglage précédent.
Un problème avec une durée de vie contrôlée par interface en général à Delphi est que la plus petite unité de portée est la procédure. C'est trop grossière. Cela fonctionne bien en C ++ car les blocs introduisent de nouvelles étendues.
@Remko Je ne pense pas que l'une des fonctions RTL sur l'appel X86 Set8087CW. Mais les implémentations de certains sur x64 font (puits, SETMXSCR sur x64 qui a la même faille que SET8087CW). Ce qui signifie que les fonctions RTL standard standard dans un thread peuvent modifier l'état de l'unité FP dans une autre. C'est un vrai choc. J'ai écrit à ce sujet ici: QC.EMBARCADERO.COM/WC/QCMAIN.ASPX? D = 107411
@DavidHeffernan, j'ai essayé de télécharger le document ci-joint dans votre rapport QC, mais le fichier a été stocké en tant que fichier .htm. Renommer le fichier à .zip corrigé le problème. Excellente analyse et proposition BTW.
@Lurd Je suppose que nous avons besoin d'un document similaire pour proposer des corrections à QC !!
J'utilise une fonction:
C'est un qnan mais la question concerne SNAN
Ah désolé. Je n'ai pas compris la différence.
Voici une façon plutôt sale de le faire, ce qui entraîne un code très propre pour le consommateur.
unit uSNaN; interface const SNaN: Double=0.0;//SNaN value assigned during initialization implementation initialization PInt64(@SNaN)^ := $7FF7FFFFFFFFFFFF; end.
Cette déclaration résout à la compilation: Le compilateur traite toujours le Essayer d'assigner un Valeur to Si vous avez la directive compileuse snan code> comme une constante. p> snan code> donnera une erreur d'heure de compilation: E2064 Le côté gauche ne peut pas être attribué à code>. p> $ witeableconsts sur code> (ou $ j + code>), cela pourrait être désactivé temporairement Pour ne pas modifier snan code>. p>
+1 Cela fait l'affaire, mais je ressentirais un peu de maquette sur la valeur qui vivant dans une variable plutôt qu'une constante.
L'attribution d'une valeur à SNAN donnera une erreur de compilateur: E2064 Le côté gauche ne peut pas être attribué à code>.
Avez-vous essayé d'inliquer votre première approche?
@Uweraabe en fait j'ai. Je voulais laisser quelqu'un d'autre à écrire cette réponse afin de pouvoir obtenir le représentant. Je me sens toujours un peu inquiet de s'appuyer sur l'inlinage. Si l'appel de la fonction n'est pas inlincé, alors flèche.