Überschreibe die Delphi-Funktion System.Round

8

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?

    
Michael 07.06.2013, 08:23
quelle

4 Antworten

14

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:

%Vor%

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.

    
David Heffernan 07.06.2013, 08:38
quelle
7
%Vor%

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%     
HeartWare 07.06.2013 11:40
quelle
1

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.

verwenden %Vor%

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.

    
Rob Kennedy 07.06.2013 15:38
quelle
0

// Banker rund um omzeilen

%Vor%     
Deathspank 18.01.2018 13:39
quelle

Tags und Links