Ich habe gerade entdeckt, dass eine Software, die ich neu implementieren muss, extensive System.Round () verwendet. Das Problem ist, dass diese Funktion "Bankers runding" verwendet und das Verhalten nicht wie in Math.RoundTo () geändert werden kann (rmDown, rmUp, rmNearest, rmTruncate).
Ich muss das Verhalten auf "normales Runden" ändern (12.5 - & gt; 13 NOT 12.5 - & gt; 12) ... Also möchte ich System.Round () global überschreiben. Ich möchte dies tun, weil Round () so oft verwendet wird und ich nicht alle manuell ändern möchte.
Wie ist das möglich?
WARNUNG : Obwohl die folgende Antwort die gestellte Frage anspricht, würde ich empfehlen, dass niemand sie jemals verwendet. Wenn Sie das Runden anders als Round
durchführen möchten, schreiben Sie eine dedizierte Funktion und rufen Sie sie an.
Sie können einen Laufzeitcode-Hook verwenden, um die Implementierung von Round
zu ändern.
Die Falte ist, dass es ein wenig schwierig ist, die Adresse der Funktion Round
zu bekommen, weil sie eine intrinsische ist. Sie müssen auch vorsichtig sein, die verwendete Aufrufkonvention zu befolgen. Der Eingabewert wird im x87-Stack-Register ST(0)
übergeben und der Rückgabewert ist eine 64-Bit-Ganzzahl in EDX:EAX
.
So geht's.
%Vor% Wenn Sie Ihre Version lieber in Pascal als in asm implementieren möchten, müssen Sie die nicht standardmäßige Aufrufkonvention von _ROUND
an die standardmäßige Delphi-Aufrufkonvention anpassen. So:
Beachten Sie, dass ich hier davon ausgegangen bin, dass Ihr Programm auf 32 Bit abzielt. Wenn Sie 64 Bit zielen müssen, dann sind die Prinzipien sehr ähnlich, aber die Details unterscheiden sich offensichtlich.
Wenn Sie das obige in MathRound.PAS in Ihrem Projektverzeichnis speichern und dieses Gerät dann in Ihre Quelldateien einfügen, haben Sie eine mathematische ROUND-Funktion anstelle der standardmäßig implementierten Bankrunden.
Es wird abgerundet -12,5 bis -12 (dh immer für Werte von 0,5 auf Null gerundet) und -12,1 bis -11. Wenn Sie eine "Logische" Rundung wünschen, sollten Sie stattdessen diese Zeile verwenden:
%Vor%als Funktionskörper.
Dies wird zu
führen %Vor% Sie sind besorgt über die Zeit und den Aufwand, die erforderlich sind, um alle vorhandenen Round
-Aufrufe manuell zu ändern, um etwas anderes aufzurufen. Also ändere sie nicht manuell. Verwenden Sie ein Werkzeug, um es zu automatisieren. Zum Beispiel könnten Sie sed.
Mit dieser Änderung ist Ihr Code nun explizit darüber, was für eine Rundung verwendet wird. Es erfordert nicht, dass jeder, der Ihren Code liest, weiß, dass ein Patch an anderer Stelle im Code angewendet wurde, um das globale Verhalten von Standardfunktionen zu beeinflussen. Es wirkt sich auch nicht auf Code aus, den Sie mit anderen Bibliotheken verknüpfen, der sich auf das Standardverhalten von Round
stützen und durch eine globale Änderung unterbrochen werden kann.