Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

OpenSource in C: Mathematik-Library für iX87, C-Inline-asm, 57 Funktionen, relativ portabel

7 views
Skip to first unread message

Helmut Schellong

unread,
Jun 16, 2022, 12:08:30 PM6/16/22
to

Helmut Schellong

unread,
Jun 21, 2022, 6:34:27 AM6/21/22
to

Dirk Krause

unread,
Jun 21, 2022, 3:13:34 PM6/21/22
to
Am 21.06.22 um 12:34 schrieb Helmut Schellong:
> On 06/16/2022 18:08, Helmut Schellong wrote:
>>
>> http://www.schellong.de/htm/math87.htm
>>
>>
>
> Update.
> Überarbeitung von allem und mehr Funktionen.
>
>

Hallo Helmut,
zuerst die Tipps, Begruendung folgt dann:

1. Nichts mehr von dieser Bibliothek hier posten, ausser wenn
Fragen oder Probleme auftreten (also keine Update-News aller
paar Tage).
2. Projekt bei OSS-Hoster anlegen.
3. Wichtige Frage beantworten: "Wozu?".

Zu 1.: Auf meinem Linux-PC befinden sich etwa 2000 shared libraries.
Die sind alle Open Source und von jemandem geschrieben, der stolz
darauf ist. In den allermeisten Faellen zu Recht. Die muessen aber
nicht alle fuer jede Aenderung die Liste hier fluten.
Und diese 2000 bei mir installierten sind laengst nicht alle, die es
weltweit gibt.
Mit dem ersten Posting haben diejenigen, die es interessiert,
Kenntnis genommen und hatten Gelegenheit, Bookmarks anzulegen...
um sich auf dem Laufenden zu halten.

Zu 2.: Da Du innerhalb weniger Tage mehrere Postings losgelassen hast,
moechtest Du vermutlich, dass andere Leute die Bibliothek benutzen.
Dann solltest Du sie dort verfuegbar machen, wo sie auch gefunden
wird, also bei Projekt-Hostern wie z.B. SourceForge, GitHub...
Dort kannst Du in der Regel Kategorien und Unterkategorien angeben,
wie "Bibliothek", "Mathematik" und Schlüsselworte wie "x87".
Damit liegt Deine Bibliothek dort, wo potentielle Verwender danach
suchen und kann dann auch gefunden werden.
Eine sinnvolle Projektbeschreibung ist auch hilfreich, siehe
naechster Punkt.
Manche OSS-Projekt-Hoster geben Nutzern die Moeglichkeit, News
bestimmter Projekte zu abonnieren. Wer das fuer Dein Projekt dann
tut, erhaelt automatisch eine E-Mail, wenn Du eine neue Version
hochgeladen oder eine Wiki-Seite geaendert hast. Damit gehen derartige
Informationen zielgenau an die Leute, die es interessiert.

Zu 3.: In der Projektbeschreibung fehlt mir die wichtigste Information
ueberhaupt:
Wieso sollte ich diese Bibliothek einsetzen? Fuer Visual Studio sagt
die Dokumentation, dass Laufzeitbibliothek und Mathematikbibliothek
beim Programmstart pruefen, welche Hardwareunterstuetzung fuer
Floating-Point-Operationen zur Verfuegung steht und dann die optimale
Hardware ansprechen. Ich gehe mal davon aus, dass gcc, clang und auch
die Borland-Compiler (oder wie immer die heute heissen) das auch
beherrschen.
Als einzigen auffindbaren Grund auf der Webseite sehe ich: "Es wurde
30 Jahre alter Assembler-Code gefunden und in eine C-Bibliothek
gepackt. Dabei traten Probleme auf, dass der Assembler-Code nicht
unveraendert weiterverwendet werden konnte. Die bisher aufgetretenen
Probleme wurden geloest.". Zusaetzlich finde ich noch die wichtige
Information, mit welchen Abmessungen das Titelblatt des originalen
Druckwerkes gescannt wurde.
Klingt das ueberzeugend?

Viele Gruesse

Dirk

Bonita Montero

unread,
Jun 22, 2022, 2:36:32 AM6/22/22
to
Am 16.06.2022 um 18:08 schrieb Helmut Schellong:
>
> http://www.schellong.de/htm/math87.htm

Hättste vor 20 Jahren verbreiten können, wo die Nutzung der
x87-FPU noch Verbreitung hatte. Seit der Einfühfung von SSE2
mit dem Pentium 4 2000 ist das Thema eigentlich durch.

Helmut Schellong

unread,
Jun 22, 2022, 10:06:24 AM6/22/22
to
https://de.wikipedia.org/wiki/X87
|Seit der Einführung von SSE2 haben x87-Einheiten viel von ihrer früheren Bedeutung verloren.
|Für Berechnungen, die eine Mantisse von 64 Bit erfordern, wie sie mit den 80 Bit breiten
|x87-Registern möglich ist, sind sie aber weiterhin wichtig.

SSE2 bringt ADD, SUB, MUL, Kehrwert, SQRT; float und double - das ist alles.
Das reicht mir aber gar nicht!

Ich bin affin mit Mathematik und hatte mich nach dem Studium
noch jahrelang damit beschäftigt.
Vor dem Studium hatte ich den TI59 mit zusätzlichen Mathe-Modulen.

Ich mußte eine Art Taschenrechner-Programm auf dem PC haben.
Das mußte ich selbst entwickeln, da es keines nach meinen Wünschen gab.
Wiederum dazu mußte ich (1991) meine iX87-Lib entwickeln, weil libmath.a ungenügend war.

Das calc-Programm mußte in der Kommandozeile sein, weil nur dann der vorherige
Rechenvorgang weithin sichtbar und kopierbar ist.
Der Rechner unter Win10 kommt meinen Forderungen nahe.
Ich arbeite aber hauptsächlich unter unixoiden Systemen.

Ich hatte einige Jahre zufriedenstellend mit meinem calc-Kommando gearbeitet.
Später mußte ich mein calc auf die C-Lib umstellen.
Da die C-Lib ungenügend war, mußte ich vieles aus meinem calc rausschmeißen.

Nun habe ich meine Lib-iX87 portabel neu gefaßt und kann mein calc wieder vervollständigen.
Ich habe halt Ansprüche, die ich nur durch Eigenentwicklung erfüllen kann.
Nun kann ich auch daran denken, den mathematischen Teil in meiner bish-Shell
mit meiner neuen Lib neu zu gestalten.

Bonita Montero

unread,
Jun 22, 2022, 2:14:14 PM6/22/22
to
Am 22.06.2022 um 16:06 schrieb Helmut Schellong:

> SSE2 bringt ADD, SUB, MUL, Kehrwert, SQRT; float und double - das ist
> alles.
> Das reicht mir aber gar nicht!

SSE kann zwar einiges mehr, aber sicher nicht alles was Du dir wünschst.
Nur ist es wie ich anderswo halt schon mal gesagt habe so, dass dieses
ganzen transzendenten Operationen als Libary-Call schneller sind als
die Realisierung im Microcode.
SSE und AVX sind einfach der vernünftigste und modernere Weg und die
x87-FPU könnten die meinentwegen in den nächsten CPU-Generationen
komplett im Microcode über die SSE- / AVX-Rechenwerke laufen lassen
und über den Anstoß per Microcode beliebig langsam sein. Mir wär es
sogar recht, wenn die den ganzen x86, V86 und 286 Protected Mode
rauswerfen, denn das nutzt eh keiner mehr und zugänglich sind die
bei aktuellen Betriebssystemen nur noch in einer VM.

> Ich mußte eine Art Taschenrechner-Programm auf dem PC haben.

Ach, und deswegen programmiert man das in Assembler ?
Ich würd mal sagen: das wär selbst in GW Basic schnell genug.

Helmut Schellong

unread,
Jun 22, 2022, 3:18:37 PM6/22/22
to
On 06/22/2022 20:14, Bonita Montero wrote:
> Am 22.06.2022 um 16:06 schrieb Helmut Schellong:
>
>> SSE2 bringt ADD, SUB, MUL, Kehrwert, SQRT; float und double - das ist alles.
>> Das reicht mir aber gar nicht!
>
> SSE kann zwar einiges mehr, aber sicher nicht alles was Du dir wünschst.

SSE2 kann nicht mehr Rechenoperationen als die aufgeführten.

> Nur ist es wie ich anderswo halt schon mal gesagt habe so, dass dieses
> ganzen transzendenten Operationen als Libary-Call schneller sind als
> die Realisierung im Microcode.
> SSE und AVX sind einfach der vernünftigste und modernere Weg und die
> x87-FPU könnten die meinentwegen in den nächsten CPU-Generationen
> komplett im Microcode über die SSE- / AVX-Rechenwerke laufen lassen
> und über den Anstoß per Microcode beliebig langsam sein. Mir wär es
> sogar recht, wenn die den ganzen x86, V86 und 286 Protected Mode
> rauswerfen, denn das nutzt eh keiner mehr und zugänglich sind die
> bei aktuellen Betriebssystemen nur noch in einer VM.

Ausschluß-Kriterium ist alleine double als größter Typ.
Ich hätte am liebsten 33-stellige Dezimal-Signifikanz, mit 128 Bit Gleitkomma.
Damit habe ich schon gearbeitet.

>> Ich mußte eine Art Taschenrechner-Programm auf dem PC haben.
>
> Ach, und deswegen programmiert man das in Assembler ?
> Ich würd mal sagen: das wär selbst in GW Basic schnell genug.
>

Ich brauche _alle_ Rechenoperationen, die iX87 kann.
Beispielsweise Divisionsrest bei Gleitkomma, um z.B. 'Ungerade' feststellen zu können.
Und mein Taschenrechner-Programm kann auch in einem Skript laufen.
Eine Art Taschenrechner-Programm ist _ein Beispiel_ von dem, was ich alles brauche.

Was der Compiler beim Umgang mit Gleitkomma benutzt, ist mir egal.
Tatsache ist, daß der iX87 in jeder iX86-CPU eingebaut ist.
Warum hat Intel den bisher nicht rausgeworfen?

Bonita Montero

unread,
Jun 23, 2022, 12:49:18 AM6/23/22
to
Am 22.06.2022 um 21:18 schrieb Helmut Schellong:
> On 06/22/2022 20:14, Bonita Montero wrote:
>> Am 22.06.2022 um 16:06 schrieb Helmut Schellong:
>>
>>> SSE2 bringt ADD, SUB, MUL, Kehrwert, SQRT; float und double - das ist
>>> alles.
>>> Das reicht mir aber gar nicht!
>>
>> SSE kann zwar einiges mehr, aber sicher nicht alles was Du dir wünschst.
>
> SSE2 kann nicht mehr Rechenoperationen als die aufgeführten.

Du bist echt soooo dämlich:
https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=SSE,SSE2
Die Intrinsics entsprechend direkt 1:1 Instruktionen.

> Ausschluß-Kriterium ist alleine double als größter Typ.

Wenn Du eine moderne C-Runtime hast, dann schaltet die dir eh die
maximale Präzision deiner FPU auf 64 Bit runter wg. der Kompatibilität
zu SSE und andren FPUs. Du musst das Control Word ändern um wieder auf
80 Bit hochzuschalten.
Außerdem haben viele Compiler das long double als 80 Bit Datentypen
verworfen und im Endeffekt ist's dann ein 64 Bit double. Du kannst
das dann ggf. per Kommandozeilen-Switch freischalten, dass der
entsprechend dann wieder mit 64 Bit arbeite.

> Ich hätte am liebsten 33-stellige Dezimal-Signifikanz, mit 128 Bit
> Gleitkomma.
> Damit habe ich schon gearbeitet.

x87 unterstützt keine 128 Bit.
Und Du brauchst das auch nicht wirklich bzw. das sind Nerd-Attitüden.

>> Ach, und deswegen programmiert man das in Assembler ?
>> Ich würd mal sagen: das wär selbst in GW Basic schnell genug.

> Ich brauche _alle_ Rechenoperationen, die iX87 kann.

Es ging gerade um die Geschwindigkeit.

> Beispielsweise Divisionsrest bei Gleitkomma, um z.B. 'Ungerade'
> feststellen zu können.

Du bist so ein Ultra-Nerd: verlierst dich in Details, ohne
den Blick für übergreifene Zusammenhänge zu haben. Ich mein
es gibt wirklich Null Notwendigkeit für dich, das ganze in
Assembler zu programmiern; in C ist das um Größenordnungen
einfacher und da sind alle Funktionen die man braucht.

> Was der Compiler beim Umgang mit Gleitkomma benutzt, ist mir egal.
> Tatsache ist, daß der iX87 in jeder iX86-CPU eingebaut ist.
> Warum hat Intel den bisher nicht rausgeworfen?

Die haben auch nicht den x86-, Vx86 und 286-Modus rausgeworfen,
obwohl das vielleicht heute noch nur noch ein Promille der Leute
nutzen.

Helmut Schellong

unread,
Jun 23, 2022, 6:07:43 AM6/23/22
to
On 06/23/2022 06:49, Bonita Montero wrote:
> Am 22.06.2022 um 21:18 schrieb Helmut Schellong:
>> On 06/22/2022 20:14, Bonita Montero wrote:
>>> Am 22.06.2022 um 16:06 schrieb Helmut Schellong:
>>>
>>>> SSE2 bringt ADD, SUB, MUL, Kehrwert, SQRT; float und double - das ist alles.
>>>> Das reicht mir aber gar nicht!
>>>
>>> SSE kann zwar einiges mehr, aber sicher nicht alles was Du dir wünschst.
>>
>> SSE2 kann nicht mehr Rechenoperationen als die aufgeführten.
>
> Du bist echt soooo dämlich:
> https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=SSE,SSE2
> Die Intrinsics entsprechend direkt 1:1 Instruktionen.

Nun gut, ich habe die Division vergessen aufzuführen.
Ändert kaum etwas.

Zur Klarstellung:
-----------------
Meine Library mit 59 Funktionen ist auf keiner X86-Plattform ersetzbar!
Keine einzige der Funktionen! - Allein wegen 80 Bit Gleitkomma (long double).
Fast alle Funktionen sind wegen ihrer Rechenoperationen nicht ersetzbar!
Beispielsweise benötigen die Umwandlungen zwischen Kartesisch und Polar
sin, cos, arctan.
Tja - X87 ist folglich notwendig!
Die 12 Trigonometrischen Funktionen sind ebenso unabdingbar!
Besonders in der Elektrotechnik: sin, cos, tan, arctan.
Ich verwende weiterhin _unersetzbar_ komplexe Rechenoperationen
für Logarithmen, Potenzen, Divisionsrest, Skalierungen mit 2^x, etc.

>> Ausschluß-Kriterium ist alleine double als größter Typ.
>
> Wenn Du eine moderne C-Runtime hast, dann schaltet die dir eh die
> maximale Präzision deiner FPU auf 64 Bit runter wg. der Kompatibilität
> zu SSE und andren FPUs. Du musst das Control Word ändern um wieder auf
> 80 Bit hochzuschalten.

Das ist mir unbekannt!
----------------------
410] a.out 11 20 4
prec=3 rnd=0
top=0
160000 4
----------------------
Ganz zu Beginn in main() ist die Precision 11 -> 64 Bit.
Ich kenne das nicht anders.

> Außerdem haben viele Compiler das long double als 80 Bit Datentypen
> verworfen und im Endeffekt ist's dann ein 64 Bit double. Du kannst
> das dann ggf. per Kommandozeilen-Switch freischalten, dass der
> entsprechend dann wieder mit 64 Bit arbeite.

Auch das ist mir unbekannt.
Wenn ich 'long double' verwende, wird das auch real verwendet!:
--------------------------------------------------------------------------
.section .rodata.cst16,"aM",@progbits,16
.p2align 4 # -- Begin function sin87l
.LCPI21_0:
.quad -8144138622222088018 # x86_fp80 0.0174532925199432957691
.short 16377
.zero 6
.text
.globl sin87l
.type sin87l,@function
sin87l: # @sin87l
.cfi_startproc
# %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
fldt 16(%rbp)
cmpl $0, deg_87(%rip)
setg %al
fldt .LCPI21_0(%rip)
fmul %st(1)
testb %al, %al
fxch %st(1)
fcmovne %st(1), %st(0)
fstp %st(1)
#APP
--------------------------------------------------------------------------
Es ist vorstehend sichtbar, daß der Compiler .quad .short .zero für
ein 'long double' anlegt. Es arbeitet auch außerhalb von #APP mit 80 Bit Gleitkomma.
Er benutzt halt selbstverständlich den X87!
Das muß er so machen - ohne spezielle Optionen dafür - es ist default.

|The precision-control (PC) field (bits 8 and 9 of the x87 FPU control word) determines the precision
|(64, 53, or 24 bits) of floating-point calculations made by the x87 FPU (see Table 8-2).
|The default precision is double extended precision, which uses the full 64-bit significand available
|with the double extended-precision floating-point format of the x87 FPU data registers.
|This setting is best suited for most applications, because it allows applications to take
|full advantage of the maximum precision available with the x87 FPU data registers.

Der X87 wandelt sämtliche Formate (auch Integer) beim Laden (fld) auf 80-Bit-Gleitkomma um.
Unabhängig von der Precision!
Der X87 wandelt beim Abspeichern (fst) das 80-Bit-Format in alle geforderten Formate um.
Unabhängig von der Precision!
Es ist folglich Unfug, die Precision zu reduzieren.
Es sei denn, bestimmte Programmiersprachen (oder ähnlich) verlangen das.
Eine reduzierte Precision bewirkt, daß einige untere Bits im Signifikanten
0-gesetzt werden bei bestimmten Instruktionen.


>> Ich hätte am liebsten 33-stellige Dezimal-Signifikanz, mit 128 Bit Gleitkomma.
>> Damit habe ich schon gearbeitet.
>
> x87 unterstützt keine 128 Bit.

Weiß ich, aber 80 Bit. SSE2 usw. maximal 64 Bit.

> Und Du brauchst das auch nicht wirklich bzw. das sind Nerd-Attitüden.

Ich könnte das gut gebrauchen.
Das weiß ich, weil ich bereits _konkret_ damit gearbeitet habe (auf HP-hw).

>>> Ach, und deswegen programmiert man das in Assembler ?
>>> Ich würd mal sagen: das wär selbst in GW Basic schnell genug.
>
>> Ich brauche _alle_ Rechenoperationen, die iX87 kann.
>
> Es ging gerade um die Geschwindigkeit.

Genau, da ist der X87 bis zu 150-fach schneller als EMUL.

>> Beispielsweise Divisionsrest bei Gleitkomma, um z.B. 'Ungerade' feststellen zu können.
>
> Du bist so ein Ultra-Nerd: verlierst dich in Details, ohne
> den Blick für übergreifene Zusammenhänge zu haben. Ich mein
> es gibt wirklich Null Notwendigkeit für dich, das ganze in
> Assembler zu programmiern; in C ist das um Größenordnungen
> einfacher und da sind alle Funktionen die man braucht.

Nein!
Aber nein!
Und nochmals nein!
Wie stelle ich fest, ob ein Gleitkommawert ungerade ist?
Ich muß das unbedingt haben!

Besonders unter Windows fehlen mir z.B. eine ganze Reihe Math-Funktionen.

>> Was der Compiler beim Umgang mit Gleitkomma benutzt, ist mir egal.
>> Tatsache ist, daß der iX87 in jeder iX86-CPU eingebaut ist.
>> Warum hat Intel den bisher nicht rausgeworfen?
>
> Die haben auch nicht den x86-, Vx86 und 286-Modus rausgeworfen,
> obwohl das vielleicht heute noch nur noch ein Promille der Leute
> nutzen.

Ich habe seit einer Reihe von Postings dargelegt, daß ich das unbedingt in
Assembler programmieren muß, um alle Funktionen zu erhalten, die ich benötige!

double a, b; /*...*/ rem= a % b;

geht z.B. nicht in C!

Man sollte mich nicht für so blöd halten, daß ich diese Library
_ohne_ triftigen Grund entwickelte!

Bonita Montero

unread,
Jun 23, 2022, 10:58:23 AM6/23/22
to
> Meine Library mit 59 Funktionen ist auf keiner X86-Plattform ersetzbar!

Da ist auch komplett egal, weil ich dir mal unterstelle, dass
Du tatsächlich nicht den geringsten Bedarf hast, das in Assembler
zu programmieren und C einfach keine Einschränkung hier wäre.
Hier Assembler zu nehmen ist als würde der Maurer statt mit der
Kelle mit dem Löffel arbeiten.

> Keine einzige der Funktionen! - Allein wegen 80 Bit Gleitkomma
> (long double).

Ich glaub dir auch kein Stück, dass Du das brauchst. Nahzu niemand
braucht das. Ich meine nichtmal bei der Berechnung von Wetter-Vor-
hersagen, wo die Fehler-Fortplanzung theoretisch eine Rolle spielen
könnte ist das relevant bzw. aus der Ecke schreit absolut keiner
nach mehr als 64 Bit FP. Und auch bei der Klima-Berechnung (Klima
!= Wetter), wo man über Simulationen fährt die Vorgänge über Jahr-
zehnte nachbilden und wo man naiverweise meinen könnte, dass man
da mehr Präzision bruacht, da interesiert das auch keinen.
Es gibt quasi außer den historischen 68K keine CPU die 80 Bit
Präzision unterstützt. Die 128 Bit FP in SPARC waren microcoded,
trapped o.Ä,; ich nehm mal an, dass das auch nahezu keiner
gebraucht hat.

> sin, cos, arctan.

Da nimmt der Nicht-Voltrottel einfach eine C Library Funktion.

> Tja - X87 ist folglich notwendig!

X87 braucht heute kein Mensch mehr und es programmiert auch keiner
mehr die FPU oder SIMD in Assembler, sondern in C / C++, ggf. halt
mit Intrinsics für SIMD; in sicher 90%+ Fällen kommt dabei auch
effizienterer Code raus.

> Auch das ist mir unbekannt.

Hast recht, nur MSVC++ und Intel-C++ haben das so gemacht.

>> x87 unterstützt keine 128 Bit.

> Weiß ich, aber 80 Bit. SSE2 usw. maximal 64 Bit.

Du bist auch der letzte den das interesiert.

>> Und Du brauchst das auch nicht wirklich bzw. das sind Nerd-Attitüden.
>
> Ich könnte das gut gebrauchen.

Mit Vernunft hat das nix zu tun.

> Genau, da ist der X87 bis zu 150-fach schneller als EMUL.

Die Größenordnungen werden heute ähnlich sein, aber sich jetzt
aus uralten Benchmarks auf heute projeziert auf 150 festzulegen
ist schon, naja ...

Bonita Montero

unread,
Jun 23, 2022, 11:05:50 AM6/23/22
to
> Nein!
> Aber nein!
> Und nochmals nein!
> Wie stelle ich fest, ob ein Gleitkommawert ungerade ist?
> Ich muß das unbedingt haben!

Dann machste ein Aliasing des Gleitkomma-Wertes in C mit Type Punning,
Bit-frickelst da selbst ein wenig herum und hast es so komfortabel wie
es eben geht. Alles andre ist einfach komplett behindert.

> Ich habe seit einer Reihe von Postings dargelegt, daß ich das unbedingt in
> Assembler programmieren muß, um alle Funktionen zu erhalten, die ich
> benötige!
>
>     double a, b; /*...*/ rem= a % b;
>
> geht z.B. nicht in C!

Geht seit C99:
https://en.cppreference.com/w/c/numeric/math/remainder

Und ich mein auch wenn das nicht ginge, dann könnte man immer
noch ein wenig inline-Assembly nehmen, aber deswegen jetzt
längere Brechnungen in Assembler zu machen ist eher schon
für Leute die von zu Hause weggelaufen sind.

Bonita Montero

unread,
Jun 23, 2022, 1:59:15 PM6/23/22
to
Am 23.06.2022 um 17:06 schrieb Bonita Montero:
>> Nein!
>> Aber nein!
>> Und nochmals nein!
>> Wie stelle ich fest, ob ein Gleitkommawert ungerade ist?
>> Ich muß das unbedingt haben!
>
> Dann machste ein Aliasing des Gleitkomma-Wertes in C mit Type Punning,
> Bit-frickelst da selbst ein wenig herum und hast es so komfortabel wie
> es eben geht. Alles andre ist einfach komplett behindert.

Ich hab das hier mal in C++ implementiert, müsste funktionieren:

bool doubleEvenOdd( double d )
{
static_assert(sizeof(double) == 8 && numeric_limits<double>::is_iec559,
"double must be 8 bytes and IEEE-754");
uint64_t i, exp;
memcpy( &i, &d, 8 );
exp = i & 0x7FF0000000000000;
if( exp < 0x3FF0000000000000 ) [[unlikely]]
return false;
if( exp == 0x3FF0000000000000 ) [[unlikely]]
return true;
if( exp > (uint64_t)(0x3FF + 52) << 52 ) [[unlikely]]
return true;
unsigned s = (unsigned)(exp >> 52) - 0x3FF;
return i & (uint64_t)0x10000000000000 >> s;
}

Is zwar C++, aber es geht ums generelle Prinzip, und das wäre in C
kein andres.
Aliasing geht in C++ sicher nur per memcpy(), aber in obigem Fall
machen alle Compiler außer MSVC ein Move von FP-Register zu Integer
-Register daraus. In C musste kein memcpy() verwenden, aber Du kannst
es ebenso bzw. das übersetzt der Compiler genauso. In C kannste alles
als ein gleich großes char-Array aliasen und ein char-Array als gleich
großes irgendwas, d.h. Du castest einfach durch char * und fertig.

Der generierte Code (g++ 11.1.x):

_Z13doubleEvenOddd:
endbr64
movabsq $9218868437227405312, %rcx
movq %xmm0, %rdx
movabsq $4607182418800017407, %rax
andq %rdx, %rcx
cmpq %rax, %rcx
jbe .L5
movabsq $4841369599423283200, %rsi
addq $1, %rax
cmpq %rax, %rcx
sete %al
cmpq %rsi, %rcx
seta %sil
orb %sil, %al
jne .L3
movabsq $4503599627370496, %rax
shrq $52, %rcx
subl $1023, %ecx
shrq %cl, %rax
testq %rdx, %rax
setne %al
ret
.L5:
xorl %eax, %eax
.L3:
ret

Ich mein so effizient kriegt man das in Assembler nur mit viel
Sachverstand hin.

Ist allerdings alles nur unter der Annahme, dass dir die Nach-
komma-Stellen unwichtig sind bzw. die nicht Null sein müssen.

Bonita Montero

unread,
Jun 23, 2022, 2:01:11 PM6/23/22
to
Am 23.06.2022 um 19:59 schrieb Bonita Montero:

>     if( exp > (uint64_t)(0x3FF + 52) << 52 ) [[unlikely]]
>         return true;

Äh, return false.
Den geänderten Disassembly poste ich mal nicht.

Helmut Schellong

unread,
Jun 23, 2022, 2:41:52 PM6/23/22
to
On 06/23/2022 17:06, Bonita Montero wrote:
>> Nein!
>> Aber nein!
>> Und nochmals nein!
>> Wie stelle ich fest, ob ein Gleitkommawert ungerade ist?
>> Ich muß das unbedingt haben!
>
> Dann machste ein Aliasing des Gleitkomma-Wertes in C mit Type Punning,
> Bit-frickelst da selbst ein wenig herum und hast es so komfortabel wie
> es eben geht. Alles andre ist einfach komplett behindert.

So etwas ist abenteuerlich.
Gleitkommaformate sind sehr variabel. Normiert z.B. Alles ist 2^x.
Und es ist nicht portabel.

>> Ich habe seit einer Reihe von Postings dargelegt, daß ich das unbedingt in
>> Assembler programmieren muß, um alle Funktionen zu erhalten, die ich benötige!
>>
>>      double a, b; /*...*/ rem= a % b;
>>
>> geht z.B. nicht in C!
>
> Geht seit C99:
> https://en.cppreference.com/w/c/numeric/math/remainder

Stimmt, diese Funktionen hatte ich vergessen.

> Und ich mein auch wenn das nicht ginge, dann könnte man immer
> noch ein wenig inline-Assembly nehmen, aber deswegen jetzt
> längere Brechnungen in Assembler zu machen ist eher schon
> für Leute die von zu Hause weggelaufen sind.

Man kann aber Überraschungen erleben.

__FBSDID("$FreeBSD: releng/11.2/lib/msun/amd64/e_remainder.S 217108 2011-01-07 16:13:12Z kib $")
ENTRY(remainder)
movsd %xmm0,-8(%rsp) ;double
movsd %xmm1,-16(%rsp)
fldl -16(%rsp)
fldl -8(%rsp)
1: fprem1
fstsw %ax
testw $0x400,%ax
jne 1b
fstpl -8(%rsp)
movsd -8(%rsp),%xmm0
fstp %st
ret

Ja, was machen die da? Sie benutzen den X87 per Assembler!
Aber 'fprem1' finde ich ungeeignet, weil die mal positive Werte
liefert und mal negative. Negative muß man vom Divisor |subtrahieren|,
um den Rest zu erhalten. Ich verwende 'fprem'.

Helmut Schellong

unread,
Jun 23, 2022, 2:49:09 PM6/23/22
to
Eben.
Ich verwende allerdings 'fprem' für 'rest = x % 2.0L;'.
Ist einfacher und sicherer.

Bonita Montero

unread,
Jun 23, 2022, 3:04:46 PM6/23/22
to
Am 23.06.2022 um 20:42 schrieb Helmut Schellong:
> On 06/23/2022 17:06, Bonita Montero wrote:
>>> Nein!
>>> Aber nein!
>>> Und nochmals nein!
>>> Wie stelle ich fest, ob ein Gleitkommawert ungerade ist?
>>> Ich muß das unbedingt haben!
>>
>> Dann machste ein Aliasing des Gleitkomma-Wertes in C mit Type Punning,
>> Bit-frickelst da selbst ein wenig herum und hast es so komfortabel wie
>> es eben geht. Alles andre ist einfach komplett behindert.

> So etwas ist abenteuerlich.

Ne, das in Assembler zu realsieren ist das eher.

> Gleitkommaformate sind sehr variabel. Normiert z.B. Alles ist 2^x.
> Und es ist nicht portabel.

Ach, und in Assembler ist es natürlich portabel - alles klar.
Du kannst doch keine drei Meter geradeaus denken.

>> Und ich mein auch wenn das nicht ginge, dann könnte man immer
>> noch ein wenig inline-Assembly nehmen, aber deswegen jetzt
>> längere Brechnungen in Assembler zu machen ist eher schon
>> für Leute die von zu Hause weggelaufen sind.

> Man kann aber Überraschungen erleben.
> ...

Guck ich mir nicht an, denn ich weiß, dass es mit ein wenig
Inline-Assembly einfacher geht. Dass man sich auch dabei auf
die Füße treten kann ist klar.

Bonita Montero

unread,
Jun 23, 2022, 3:14:57 PM6/23/22
to
Am 23.06.2022 um 20:49 schrieb HelmutSchellong :
> Eben.
> Ich verwende allerdings 'fprem' für 'rest = x % 2.0L;'.
> Ist einfacher und sicherer.

Ich hab's mal gerade nachgeschaut:
FPREM hat auf einer modernen Zen3-CPU 24 - 70 Takte Latenz.
Aber eigentlich ist mir die Performance wichtig, dir ja nicht
denn Du programmierst ja Assembler. ;-)

Helmut Schellong

unread,
Jun 23, 2022, 6:05:16 PM6/23/22
to
Ich finde das recht schnell.
Typisch dürften das ungefähr 15 ns sein.
Dafür habe ich eine Gleitkomma-Instruktion, die uneingeschränkt
mit 80-Bit-Gleitkomma mit vollem Wertbereich umgehen kann.

Die Mantisse mit 64 Bit ist auch noch dynamisch aufgeteilt in unterschiedliche Bit-Arten.
Je nach Wert.
Dann gibt es manchmal eine implizite 1, oder das Gegenteil.
Ohne Not will ich da nicht mit Bits rumfrickeln.

In den Quellen von FreeBSD wird das ziemlich genau so gemacht, wie ich das mache.
Es gibt da Assembler-Dateien wie auch Inline-Assembler.
Besonders doof kann das folglich nicht sein, was ich mache.
Wozu denn gibt es denn den Inline-Assembler?
Damit er nicht angewandt wird?
Für andere Plattformen als X86 sieht man in der Regel Funktionen mit gleicher Aufgabe,
die jedoch etwa 100 Zeilen normales C enthalten, statt 7 Assembler-Zeilen...

Bonita Montero

unread,
Jun 23, 2022, 10:00:46 PM6/23/22
to
Am 24.06.2022 um 00:05 schrieb Helmut Schellong:

> Ich finde das recht schnell.
> Typisch dürften das ungefähr 15 ns sein.

Auf meinem 3990X 13,8ns wenn nur ein Thread rechnet (4,3GHz).

> Dafür habe ich eine Gleitkomma-Instruktion, die uneingeschränkt
> mit 80-Bit-Gleitkomma mit vollem Wertbereich umgehen kann.

Wetten, dass ich das mit meiner Aliasing-Logik etwas aufgeblasen
ganz ohne Assembler in C / C++ ein Vielfaches schneller hinkriege ?
Abgesehen davon bezweifle ich weiterhin, dass Du die 80 Bit wirklich
brauchst.

> Die Mantisse mit 64 Bit ist auch noch dynamisch aufgeteilt in
> unterschiedliche Bit-Arten.

Ja, sehr inhomogen und nicht nach IEEE-754 genormt.

> Wozu denn gibt es denn den Inline-Assembler?
> Damit er nicht angewandt wird?

Man kann's auch übertreiben und dort längere Berechnungen
durchführen die man überwiegend auch in C hätte machen können.



Bonita Montero

unread,
Jun 23, 2022, 10:12:34 PM6/23/22
to
Am 24.06.2022 um 04:01 schrieb Bonita Montero:

>> Die Mantisse mit 64 Bit ist auch noch dynamisch aufgeteilt in
>> unterschiedliche Bit-Arten.

> Ja, sehr inhomogen und nicht nach IEEE-754 genormt.

Ich dachte mir gerade, ich programmier das Gerade-/Ungerade-Ding
mal für x87 extended precision nach und da hab ich mir die genaue
Definition des Exponenten und der Mantisse hier angeschaut:
https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format
Ich mein da rollen einem ja die Fußnägel auf.

Bonita Montero

unread,
Jun 23, 2022, 11:01:12 PM6/23/22
to
Ich hab dein Even-Odd-Zaug mal für x87 extended precision
implementiert:

#include <cstdint>
#include <cstring>
#include <cfenv>
#include <bit>

using namespace std;

bool xpOdd( long double d )
{
static_assert(sizeof(long double) >= 10, "long double must be >= 10
bytes");
static_assert(endian::native == endian::little, "machine must have
little endian");
uint64_t p[2] = { 0, 0 };
memcpy( &p, &d, sizeof(long double) );
unsigned e = p[1] & 0x7FFF;
if( e < 0x3FFF ) [[unlikely]]
return false;
if( e >= 0x3FFF + 64 ) [[unlikely]]
{
if( e == 0x7FFF ) [[unlikely]]
feraiseexcept( FE_INVALID );
return true;
}
unsigned s = e - 0x3FFF;
return p[0] & 0x8000000000000000u >> s;
}

Ich hab's diesmal etwas sauberer gemacht als die double precision Lösung
vorher und bei einem maximalen Exponenten, also Inf und NaN, zwar einen
sinnlosen Wert zurückgegeben, denn Inf und NaN sind ja nicht wirklich
gerade oder ungerade, aber parallel noch im Sinne von IEEE-754 und C /
C++ das entsprechende Exception-Flag gesetzt.
War doch einfacher als ich mir dachte.
Mit dem MSVC gibt'S dann eine Funktion _set_se_translator(), die soge-
nannte SEH-Exeptions abfangen kann und eine solche wird dann eben gene-
riert wenn die FPU so konfiguriert ist, dass die auch Traps wirft; das
wäre dann sowas wie SIGFPE, nur tausendfach komfortabler. Würde man aus
der Funktion die ich _set_se_translator() gebe dann eine C++ Exception
werfen (geht glaub ich aus einem Signal-Handler der SIGFPE unter Gnu-C++
fängt nicht), dann hab ich den Komfort als würde ich Java programmieren.

Auf jeden Fall ist folgendes das Disassembly von g++ 11.1.x:


_Z5xpOdde:
movq 16(%rsp), %rcx
andl $32767, %ecx
cmpl $16382, %ecx
jbe .L3
cmpl $16446, %ecx
ja .L4
movabsq $-9223372036854775808, %rax
subl $16383, %ecx
shrq %cl, %rax
movq %rax, %rdx
movq 8(%rsp), %rax
testq %rax, %rdx
setne %al
ret
.L3:
xorl %eax, %eax
ret
.L4:
movl $1, %eax
ret

Ich mein das dürfte Performance-mäßig echt über jeden Zweifel
erhaben sein.

Helmut Schellong

unread,
Jun 24, 2022, 2:07:49 AM6/24/22
to
On 06/24/2022 04:01, Bonita Montero wrote:
> Am 24.06.2022 um 00:05 schrieb Helmut Schellong:
>
>> Ich finde das recht schnell.
>> Typisch dürften das ungefähr 15 ns sein.
>
> Auf meinem 3990X 13,8ns wenn nur ein Thread rechnet (4,3GHz).
>
>> Dafür habe ich eine Gleitkomma-Instruktion, die uneingeschränkt
>> mit 80-Bit-Gleitkomma mit vollem Wertbereich umgehen kann.
>
> Wetten, dass ich das mit meiner Aliasing-Logik etwas aufgeblasen
> ganz ohne Assembler in C / C++ ein Vielfaches schneller hinkriege ?

Nein, die Erfahrung zeigt, daß Hardware _immer_ um Welten schneller ist.
Es geht hier um Gleitkomma-Divisionsrest.

> Abgesehen davon bezweifle ich weiterhin, dass Du die 80 Bit wirklich
> brauchst.

Du bist also ein Hellseher?
Nein, Du stellst einfach falsche Behauptungen auf!
Es kommt immer darauf an, _wofür_ man Gleitkomma einsetzen will.

>> Die Mantisse mit 64 Bit ist auch noch dynamisch aufgeteilt in unterschiedliche Bit-Arten.
>
> Ja, sehr inhomogen und nicht nach IEEE-754 genormt.

Nein, jedes beliebige Gleitkomma-Format hat diese Eigenschaft.
Die Mantisse hat je nach Wert einen unterschiedlich großen Ganzzahlteil
und denjenigen Teil, der kein Ganzzahlteil ist.

>> Wozu denn gibt es denn den Inline-Assembler?
> > Damit er nicht angewandt wird?
>
> Man kann's auch übertreiben und dort längere Berechnungen
> durchführen die man überwiegend auch in C hätte machen können.
>
>

Überwiegend reicht nicht.
Für mich muß es 100% homogen und optimal sein, bei bestimmten Zwecken.
Ich habe berichtet, was mir bei C-Lösungen passiert war.
Bisher mußte ich da stets ziemlichen Verzicht üben
und Projekte stark unausgefüllt lassen.
Mit meiner eigenen Library passiert das nicht, denn die ist ultimativ.

Helmut Schellong

unread,
Jun 24, 2022, 2:32:52 AM6/24/22
to
Wieso denn das?
Das war doch Ende der 1970er ein guter Kompromiß.
Das Format liegt halt zwischen 64-Bit und 128-Bit.

Bonita Montero

unread,
Jun 24, 2022, 4:05:32 AM6/24/22
to
Am 24.06.2022 um 08:33 schrieb Helmut Schellong:
> On 06/24/2022 04:13, Bonita Montero wrote:
>> Am 24.06.2022 um 04:01 schrieb Bonita Montero:
>>
>>>> Die Mantisse mit 64 Bit ist auch noch dynamisch aufgeteilt in
>>>> unterschiedliche Bit-Arten.
>>
>>> Ja, sehr inhomogen und nicht nach IEEE-754 genormt.
>>
>> Ich dachte mir gerade, ich programmier das Gerade-/Ungerade-Ding
>> mal für x87 extended precision nach und da hab ich mir die genaue
>> Definition des Exponenten und der Mantisse hier angeschaut:
>> https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format
>>
>> Ich mein da rollen einem ja die Fußnägel auf.
>
> Wieso denn das?
> Das war doch Ende der 1970er ein guter Kompromiß.
> Das Format liegt halt zwischen 64-Bit und 128-Bit.

Und wie man heute sieht, wo die Ansprüche deutlich höher sind,
weiß immer noch keiner was mit FP-Zahlen > 64 Bit anzufangen.
Das geht sogar so weit, dass x86 und 68K die einzigen Plattformen
sind bzw. waren, die das unterstützt haben.
Heutige HPC-Cluster rechnen hauptsächlich mit GPU-Derivaten und
doppelter Präzision, und das geht dann sogar so weit, das die
nichtmal denormale Zahlen beherrschen, d.h. die Präzision ist
nach unten hin auch noch abgeschnitten.

Bonita Montero

unread,
Jun 24, 2022, 4:13:25 AM6/24/22
to
Am 24.06.2022 um 08:08 schrieb Helmut Schellong:

>> Wetten, dass ich das mit meiner Aliasing-Logik etwas aufgeblasen
>> ganz ohne Assembler in C / C++ ein Vielfaches schneller hinkriege ?

> Nein, die Erfahrung zeigt, daß Hardware _immer_ um Welten schneller ist.
> Es geht hier um Gleitkomma-Divisionsrest.

Es gibt aber keine x87-Funktion die direkt feststellt, ob ein FP-Wert
gerade oder ungerade ist.
Und so generell ist diese Aussage auch nicht korrekt, denn ich habe
dir bereits gesagt, dass transzendente Operationen in Software schneller
sind als dieser Mix aus Hardware und Microcode bei x87 - durchgängig.

> Du bist also ein Hellseher?
> Nein, Du stellst einfach falsche Behauptungen auf!
> Es kommt immer darauf an, _wofür_ man Gleitkomma einsetzen will.

Nicht mal bei der Klima-Simulation mit Fehler-Fortplanzung bis
sonstwohin braucht man das, aber Du brauchst das - alles klar.

> Nein, jedes beliebige Gleitkomma-Format hat diese Eigenschaft.

Nein, die Codierung von x87 extended precision ist viel komplexer,
nicht nach IEEE-754 definiert und unterschiedliche CPU-Generationen
mit den ersten x87-FPUs haben die auch unterschiedlich intepretiert:
https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format

> Überwiegend reicht nicht.
> Für mich muß es 100% homogen und optimal sein, bei bestimmten Zwecken.

Homogenität ist hier eher eine mentale Aussage und nix was realen
Nutzen hat.

> Ich habe berichtet, was mir bei C-Lösungen passiert war.

Vielleicht kannst Du es auch nicht.
Ich mein Du kanntest bis gestern remainder() nicht.

> Bisher mußte ich da stets ziemlichen Verzicht üben

Ne, Du musst nur von deinen Zwängen abweichen.
In Sachen Performance machst Du da keine Abstriche.
In Sachen Komfort und Wartbarkeit würdest Du massiv gewinnen.

> und Projekte stark unausgefüllt lassen.
> Mit meiner eigenen Library passiert das nicht, denn die ist ultimativ.

Echt, unfassbar.
Du hast nen Programmier-Stil wie vor 30 Jahren.

Helmut Schellong

unread,
Jun 24, 2022, 4:32:54 AM6/24/22
to
> [...]
> Ich mein das dürfte Performance-mäßig echt über jeden Zweifel
> erhaben sein.

416] a.out 90 111.2345
prec=3 rnd=0
0_100000000000101_1101111001111000000100000110001001001101110100101111000110101010
top=0
111.2345 0
417] a.out 16 111.2345 2
prec=3 rnd=0
top=0
1.2345 2
----------------------------------------------------------------
Entspricht das Deinen Erwartungen?
417] ist FPREM in rem87l(111.2345, 2), Remainder = 1.2345

Die Feststellung von Ungerade brauche ich in der pow87l().

Helmut Schellong

unread,
Jun 24, 2022, 4:40:16 AM6/24/22
to
Für Dich ist das offenbar eine sehr flache mathematische Welt.
Für mich und Millionen Andere nicht.
Ich schrieb doch, daß ich schon mal konkret mit 128-bit-Gleitkomma gearbeitet
habe (PA-RISC).
Das ist absolut wichtig und unverzichtbar für die Leute im betreffenden Haus.

Bonita Montero

unread,
Jun 24, 2022, 4:49:38 AM6/24/22
to
Ich weiß nicht, was dein Code da macht, aber dein FPREM braucht
auf meiner TR3990X Zen2-CPU 12 - 60 Takte. Das bisschen Integer
Bit-Frickelei da oben liegt da sicher ne Größenordnung drunter.

Bonita Montero

unread,
Jun 24, 2022, 4:50:28 AM6/24/22
to
Am 24.06.2022 um 10:40 schrieb Helmut Schellong:

> Für Dich ist das offenbar eine sehr flache mathematische Welt.

Ja, für alle außer dich.

> Ich schrieb doch, daß ich schon mal konkret mit 128-bit-Gleitkomma
> gearbeitet habe (PA-RISC).

Und warum ist das ausgestorben ?

Helmut Schellong

unread,
Jun 24, 2022, 4:53:03 AM6/24/22
to
On 06/24/2022 10:13, Bonita Montero wrote:
> Am 24.06.2022 um 08:08 schrieb Helmut Schellong:
>
>>> Wetten, dass ich das mit meiner Aliasing-Logik etwas aufgeblasen
>>> ganz ohne Assembler in C / C++ ein Vielfaches schneller hinkriege ?
>
>> Nein, die Erfahrung zeigt, daß Hardware _immer_ um Welten schneller ist.
>> Es geht hier um Gleitkomma-Divisionsrest.
>
> Es gibt aber keine x87-Funktion die direkt feststellt, ob ein FP-Wert
> gerade oder ungerade ist.

Doch, fprem und fprem1.
remainder = x / 2.0;
liefert direkt die Eigenschaft Ungerade|Gerade.

> Und so generell ist diese Aussage auch nicht korrekt, denn ich habe
> dir bereits gesagt, dass transzendente Operationen in Software schneller
> sind als dieser Mix aus Hardware und Microcode bei x87 - durchgängig.

Nein, sie sind mindestens 30-fach langsamer.

>> Du bist also ein Hellseher?
>> Nein, Du stellst einfach falsche Behauptungen auf!
>> Es kommt immer darauf an, _wofür_ man Gleitkomma einsetzen will.
>
> Nicht mal bei der Klima-Simulation mit Fehler-Fortplanzung bis
> sonstwohin braucht man das, aber Du brauchst das - alles klar.

Ich und Millionen Andere brauchen das.

>> Nein, jedes beliebige Gleitkomma-Format hat diese Eigenschaft.
>
> Nein, die Codierung von x87 extended precision ist viel komplexer,
> nicht nach IEEE-754 definiert und unterschiedliche CPU-Generationen
> mit den ersten x87-FPUs haben die auch unterschiedlich intepretiert:
> https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format

Alle Gleitkommaformate sind prinzipiell gleich.
Lediglich die Bitbreiten von zwei Feldern sind unterschiedlich, und
manchmal ist das Integer-Bit explizit, manchmal implizit.

>> Überwiegend reicht nicht.
>> Für mich muß es 100% homogen und optimal sein, bei bestimmten Zwecken.
>
> Homogenität ist hier eher eine mentale Aussage und nix was realen
> Nutzen hat.

Homogenität ist in Technik und Wissenschaft absolut wichtig.

>> Ich habe berichtet, was mir bei C-Lösungen passiert war.
>
> Vielleicht kannst Du es auch nicht.
> Ich mein Du kanntest bis gestern remainder() nicht.

Doch, fmod() kannte ich schon immer, aber remainder() hatte ich vergessen.

>> Bisher mußte ich da stets ziemlichen Verzicht üben
>
> Ne, Du musst nur von deinen Zwängen abweichen.
> In Sachen Performance machst Du da keine Abstriche.
> In Sachen Komfort und Wartbarkeit würdest Du massiv gewinnen.

Nein, ich würde verlieren.
Ich habe doch schon mehrmals verloren, durch Projektlücken!
Habe ich doch geschrieben!
Mit meiner Lib verliere ich nicht.

>> und Projekte stark unausgefüllt lassen.
>> Mit meiner eigenen Library passiert das nicht, denn die ist ultimativ.
>
> Echt, unfassbar.
> Du hast nen Programmier-Stil wie vor 30 Jahren.

Nein, ich baue mir das, was ich unbedingt brauche.

Helmut Schellong

unread,
Jun 24, 2022, 4:59:20 AM6/24/22
to
Ich habe doch vorstehend beschrieben, was mein Code da macht.
Das sind offensichtlich Aufrufe meines Test-Kommandos.

> auf meiner TR3990X Zen2-CPU 12 - 60 Takte. Das bisschen Integer
> Bit-Frickelei da oben liegt da sicher ne Größenordnung drunter.

Funktioniert die Bit-Frickelei denn einwandfrei in allen Lagen?

Helmut Schellong

unread,
Jun 24, 2022, 5:02:35 AM6/24/22
to
On 06/24/2022 10:51, Bonita Montero wrote:
> Am 24.06.2022 um 10:40 schrieb Helmut Schellong:
>
>> Für Dich ist das offenbar eine sehr flache mathematische Welt.
>
> Ja, für alle außer dich.

Ich schrieb, für mich und Millionen Andere.

>> Ich schrieb doch, daß ich schon mal konkret mit 128-bit-Gleitkomma gearbeitet habe (PA-RISC).
>
> Und warum ist das ausgestorben ?

PA-RISC wurde durch Neueres ersetzt.
Im Serverbereich wird nach wie vor 128 Bit FP geboten.
Standardisiert sind bis 256 Bit FP.

Bonita Montero

unread,
Jun 24, 2022, 7:00:41 AM6/24/22
to
Am 24.06.2022 um 10:59 schrieb Helmut Schellong:

>> auf meiner TR3990X Zen2-CPU 12 - 60 Takte. Das bisschen Integer
>> Bit-Frickelei da oben liegt da sicher ne Größenordnung drunter.

> Funktioniert die Bit-Frickelei denn einwandfrei in allen Lagen?

Was für eine blöde Verlegenheits-Frage.

Bonita Montero

unread,
Jun 24, 2022, 7:02:03 AM6/24/22
to
Am 24.06.2022 um 11:02 schrieb Helmut Schellong:

>> Und warum ist das ausgestorben ?

> PA-RISC wurde durch Neueres ersetzt.

Es rechnet aber heute nahezu keiner mit 80 oder 128 Bit FP.

> Im Serverbereich wird nach wie vor 128 Bit FP geboten.

Aber nicht in Hardware, sondern im Microcode.

> Standardisiert sind bis 256 Bit FP.

Wirst Du sicher keine HW-Implementation finden, außer Du
backst die dir als FPGA selbst.

Bonita Montero

unread,
Jun 24, 2022, 7:18:40 AM6/24/22
to
Am 24.06.2022 um 10:53 schrieb Helmut Schellong:

>> Es gibt aber keine x87-Funktion die direkt feststellt, ob ein FP-Wert
>> gerade oder ungerade ist.

> Doch, fprem und fprem1.
>     remainder = x / 2.0;
> liefert direkt die Eigenschaft Ungerade|Gerade.

Erstens ist FPEM verglleichsweise langsam. Zweitens hat das Ergebnis
zwei mögliche Exponenten anhand derer Du gerade und ungerade unter-
scheiden kannst (>= 0.0 vs. >= 1.0). D.h. ein wenig Bit-Frickelei
ist dennoch nötig.
Ich mein: da kann man doch direkt die schnellere Lösung nehmen.

>> Und so generell ist diese Aussage auch nicht korrekt, denn ich habe
>> dir bereits gesagt, dass transzendente Operationen in Software schneller
>> sind als dieser Mix aus Hardware und Microcode bei x87 - durchgängig.

> Nein, sie sind mindestens 30-fach langsamer.

Ich hab gerade mal die sin()-Implementation meiner MSVC 2022 Runtime
gegen FSIN getestet. Das mit dem FSIN musste ich händisch in eine
Assembler-Funktion packen weil im 64 Bit Mode mit meinem Compiler
keine x87-Kompilierung mehr möglich ist.
Also hier ist der C++20-Source:

#define _USE_MATH_DEFINES
#include <random>
#include <cmath>
#include <chrono>
#include <atomic>
#include <chrono>
#include <iostream>

using namespace std;
using namespace chrono;

void deppenSin( double const &value, double &sin_ );

int main()
{
constexpr size_t
N_VALUES = 1000,
ROUNDS = 100'000;
atomic<double> aSum;
vector<double> values( N_VALUES );
mt19937_64 mt;
uniform_real_distribution<double> pmPi( -M_PI, M_PI );
for( double &v : values )
v = pmPi( mt );
auto sinCosBench = [&]<typename SinCosFn>( SinCosFn sinCosFn ) -> double
requires requires( SinCosFn sinCosFn, double const &value, double &sin
) { { sinCosFn( value, sin ) }; }
{
auto start = high_resolution_clock::now();
double sum = 0.0, sin_;
for( size_t r = ROUNDS; r--; )
for( double const &v : values )
sinCosFn( v, sin_ ),
sum += sin_;
aSum += sum;
return (double)(int64_t)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / ((double)ROUNDS *
N_VALUES);
};
double
depp = sinCosBench( deppenSin ),
std = sinCosBench( []( double const &value, double &sin_ ) { sin_ =
sin( value ); } );
cout << depp << " / " << std << endl;
}

Hier das minimale Stück Assembler:

PUBLIC ?deppenSin@@YAXAEBNAEAN@Z

_TEXT SEGMENT
?deppenSin@@YAXAEBNAEAN@Z PROC
fld qword ptr [rcx]
fsin
fstp qword ptr [rdx]
ret
?deppenSin@@YAXAEBNAEAN@Z ENDP
_TEXT ENDS

END

Resultat:

24.6788 / 10.3027

D.h. das sind() meiner Runtime ist fast genau 2,4 mal so schnell
wie FSIN.
Und bei mir ist es so, dass die Operationen für das sin() der
Runtime eine lange Kaskade von Instruktionen sind, während das
FSIN eine Operation ist, die auf meiner CPU bis zu 170 Takte
dauern kann, wo sich das nächste FSIN aber mehr als 100 Takte
out of order mit dem vorherigen überlappen kann. Gehe ich also
hin und beziehe das letzte Ergebnis in das nächste FSIN ein,
dann habe ich Latenz = Durchsatz und FSIN ist an der Stelle
dann sicher nichtmal halb so schnell.

> Ich und Millionen Andere brauchen das.

Du hast son Sockenschuss, dass ich dir das nicht abnehme.


>> https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format

> Alle Gleitkommaformate sind prinzipiell gleich.

Bei IEEE-754 und obigem - lies den Link - würde ich eher von
ähnlich sprechen.

> Lediglich die Bitbreiten von zwei Feldern sind unterschiedlich,
> und manchmal ist das Integer-Bit explizit, manchmal implizit.

Äh, hast Du dir vielleicht mal die Tabelle unter obigem Link
angeschaut ? In x87 extended precision stecken wirklich ne
ganze Menge mehr Feinheiten drin und die ersten Generationen
der x87-FPUs haben bzgl. dieser Feinheiten eben gravierende
Unterschiede gemacht.

> Homogenität ist in Technik und Wissenschaft absolut wichtig.

An der Stelle haben deine Zwänge absolut keine Vorteile.

> Nein, ich würde verlieren.
> Ich habe doch schon mehrmals verloren, durch Projektlücken!
> Habe ich doch geschrieben!
> Mit meiner Lib verliere ich nicht.

Wer solche Zwänge hat wie Du, der verliert damit überall
im Leben, nicht nur bei der SW-Entwicklung.

Bonita Montero

unread,
Jun 24, 2022, 7:28:58 AM6/24/22
to
Am 24.06.2022 um 13:19 schrieb Bonita Montero:

> D.h. das sind() meiner Runtime ist fast genau 2,4 mal so schnell
> wie FSIN.
> Und bei mir ist es so, dass die Operationen für das sin() der
> Runtime eine lange Kaskade von Instruktionen sind, während das
> FSIN eine Operation ist, die auf meiner CPU bis zu 170 Takte
> dauern kann, wo sich das nächste FSIN aber mehr als 100 Takte
> out of order mit dem vorherigen überlappen kann. Gehe ich also
> hin und beziehe das letzte Ergebnis in das nächste FSIN ein,
> dann habe ich Latenz = Durchsatz und FSIN ist an der Stelle
> dann sicher nichtmal halb so schnell.

Ganz so schlimm sieht's doch nicht aus bzw. ich habe jetzt mal
experimentell eine Abhängigkeits-Kette zwischen dem letzten
Ergebnis und dem nächsten Operanden hergestellt, dass entsprechend
nicht mehrere FSINs out of order überlappend ausgeführt weren
können:

#define _USE_MATH_DEFINES
#include <random>
#include <cmath>
#include <chrono>
#include <atomic>
#include <chrono>
#include <iostream>

using namespace std;
using namespace chrono;

void deppenSin( double const &value, double &sin_ );

int main()
{
constexpr size_t
N_VALUES = 1000,
ROUNDS = 100'000;
atomic_int64_t aISum;
vector<double> values( N_VALUES );
mt19937_64 mt;
uniform_real_distribution<double> pmPi( -M_PI, M_PI );
for( double &v : values )
v = pmPi( mt );
auto sinCosBench = [&]<typename SinCosFn>( SinCosFn sinCosFn ) -> double
requires requires( SinCosFn sinCosFn, double const &value, double &sin
) { { sinCosFn( value, sin ) }; }
{
auto start = high_resolution_clock::now();
double lastSin;
atomic_int64_t aILastValue = 0;
for( size_t r = ROUNDS; r--; )
for( double &v : values )
{
int64_t iValue;
memcpy( &iValue, &v, 8 );
iValue ^= aILastValue;
memcpy( &v, &iValue, 8 );
sinCosFn( v, lastSin ),
memcpy( &iValue, &v, 8 );
aILastValue.store( iValue, memory_order_relaxed );
aILastValue.store( 0 );
}
aISum += aILastValue;
return (double)(int64_t)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / ((double)ROUNDS *
N_VALUES);
};
double
depp = sinCosBench( deppenSin ),
std = sinCosBench( []( double const &value, double &sin_ ) { sin_ =
sin( value ); } );
cout << depp << " / " << std << endl;
}

Der Asm-Code ist der Selbe, Resultat:

27.986 / 7.89144

Also sind wir jetzt bei Faktor 3,55.

Bonita Montero

unread,
Jun 24, 2022, 9:02:47 AM6/24/22
to
So, ich habe meinen Code noch mehr aufgeblasen, dass der nicht nur
FSIN gg. sin() vergleicht, sondern noch FTAN gg. tan() sowie FPREM
gg. remainder(). Unter Windows x64 ist es ja so, dass die FPU durch-
aus noch nutzbar ist, wie man ja an dem bisherigen Vergleich ja sehen
kann. Bei sin() und tan() war mir ja klar, dass das alles in Software
realisiert wird bzw. dass man da keine Umwege über die FPU nimmt,
aber bei remainder() dachte ich mir, dass die vielleicht doch die
x87-FPU nutzen.
Der aufgeblasene Code sieht jetzt so aus:

#define _USE_MATH_DEFINES
#include <random>
#include <cmath>
#include <chrono>
#include <atomic>
#include <chrono>
#include <iostream>

using namespace std;
using namespace chrono;

void deppenSin( double const &value, double &sin_ );
void deppenTan( double const &value, double &tan_ );
void deppenRem( double const &value, double &rem_ );

template<typename TransFn>
concept trans_concept = requires( TransFn transFn, double const &value,
double &ret ) { { transFn( value, ret ) }; };

int main()
{
size_t const
N_VALUES = 1000,
#if defined(NDEBUG)
ROUNDS = 100'000;
#else
ROUNDS = 1'000;
#endif
atomic_int64_t aISum;
vector<double> values( N_VALUES );
auto compareTrans = [&]<trans_concept Native, trans_concept Lib>( char
const *description, Native native, Lib lib )
{
auto transBench = [&]<trans_concept TransFn>( TransFn transFn ) -> double
{
auto start = high_resolution_clock::now();
double lastTrans;
atomic_int64_t aILastValue = 0;
for( size_t r = ROUNDS; r--; )
for( double &v : values )
{
int64_t iValue;
memcpy( &iValue, &v, 8 );
iValue ^= aILastValue.load( memory_order_relaxed );
memcpy( &v, &iValue, 8 );
transFn( v, lastTrans ),
memcpy( &iValue, &lastTrans, 8 );
aILastValue.store( iValue, memory_order_relaxed );
aILastValue.store( 0 );
}
aISum += aILastValue;
return (double)(int64_t)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / ((double)ROUNDS *
N_VALUES);
};
double
tNative = transBench( native ),
tLib = transBench( lib ),
pct = trunc( tNative / tLib * 1'000.0 + 0.5 ) / 10.0;
cout << description << ": " << tNative << ", " << tLib << ", " << pct
<< "%" << endl;
};
mt19937_64 mt;
{
uniform_real_distribution<double> pmPi( -M_PI, M_PI );
for( double &v : values )
v = pmPi( mt );
}
compareTrans( "FSIN vs sin()", deppenSin, []( double const &value,
double &ret ) { ret = sin( value ); } );
compareTrans( "FTAN vs tan()", deppenTan, []( double const &value,
double &ret ) { ret = tan( value ); } );
{
uniform_real_distribution<double> rndValues( 0.0, ((uint64_t)1 << 53)
- 1 );
for( double &v : values )
v = rndValues( mt );
}
compareTrans( "FPREM vs remainder()", deppenRem, []( double const
&value, double &ret ) { ret = remainder( value, 2.0 ); } );
}

PUBLIC ?deppenSin@@YAXAEBNAEAN@Z
PUBLIC ?deppenTan@@YAXAEBNAEAN@Z

_DATA SEGMENT
?TWO@@3NC DQ 04000000000000000r
_DATA ENDS

_TEXT SEGMENT
?deppenSin@@YAXAEBNAEAN@Z PROC
fld qword ptr [rcx]
fsin
fstp qword ptr [rdx]
ret
?deppenSin@@YAXAEBNAEAN@Z ENDP

?deppenTan@@YAXAEBNAEAN@Z PROC
fld qword ptr [rcx]
fptan
fstp qword ptr [rdx]
ret
?deppenTan@@YAXAEBNAEAN@Z ENDP

?deppenRem@@YAXAEBNAEAN@Z PROC
fld qword ptr ?TWO@@3NC
fld qword ptr [rcx]
fprem
fxch st(1)
fstp st(0)
fstp qword ptr [rdx]
ret
?deppenRem@@YAXAEBNAEAN@Z ENDP
_TEXT ENDS

END

Wenn man das wirklich versteht, dann sieht man auch, was C++20 für
eine gigantisch mächtige Sprache ist. Das generische Lambda ließe
sich auch mit Makros realisieren, aber sowas will keiner der nicht
schlimme Dinge erlebt hat ernsthaft programmieren.
Auf jeden Fall sind das die Ergebnisse:

FSIN vs sin(): 29.2301, 13.4287, 217.7%
FTAN vs tan(): 22.0681, 16.8505, 131%
FPREM vs remainder(): 16.7135, 15.9596, 104.7%

Ich hatte bei meinem ersten Benchmark noch einen kleinen Bug drin wo ich
die Abhängigkeits-Ketten hergesellt haben wollte, aber dann im Endeffekt
keine zustandekamen, dass aus einem Unterschied zwischen FSIN und sin()
von 2,4 dann 3,55 wurde. Ich mein das war ein Fehler, aber ich find das
absolut enorm, dass da wo es dann tatsächlich keine Abhängigkeits-Ketten
gab die Pipe die längeren Instruktions-Sequenzen
in sin() mit unterschiedlichen Operanden so weit instruktions-parallel
ausführt, dass dabei so ein wahnsinns Gewinn zustandekommt.
Bei sin() ist es ja wirklich ausgeschlossen, dass der Code intern
entsprechend FSIN() nutz. Bei tan() und remainder() habe ich es nicht
ausschließen können bzw. dachte, auch wenn ich es für unwahrscheinlich
hielt, dass der Wrapping-Code den Unterschied macht.
Auf jeden Fall habe ich mir dann doch mal ein Mini-Programm geschrieben,
das die Funktionen im Release-Code im Debugger aufrief. In beiden Fällen
war es dann so, dass intern kein FRAN oder FPREM genutzt wurde, sondern
Code mit unzähligen SSE-Operationen.

So Helmut, wie war das nochmal mit 30 mal langsamer ?

Helmut Schellong

unread,
Jun 24, 2022, 10:19:18 AM6/24/22
to
Ohne Tests - das geht gar nicht.
Ich muß diese Sache folglich archivieren.
Ich sagte schon, der Grad der Portabilität ist mir nicht hoch genug.
Dieser Grad ist bei Verwendung des Erweiterten Inline-Assembling viel höher.

Helmut Schellong

unread,
Jun 24, 2022, 11:39:17 AM6/24/22
to
On 06/24/2022 13:02, Bonita Montero wrote:
> Am 24.06.2022 um 11:02 schrieb Helmut Schellong:
>
>>> Und warum ist das ausgestorben ?
>
>> PA-RISC wurde durch Neueres ersetzt.
>
> Es rechnet aber heute nahezu keiner mit 80 oder 128 Bit FP.

Hunderttausende oder Millionen rechnen mit 128-Bit-FP.
Du behauptest Dir die Welt so zurecht, wie es Dir gefällt.

>> Im Serverbereich wird nach wie vor 128 Bit FP geboten.
>
> Aber nicht in Hardware, sondern im Microcode.

Microcode arbeitet ja in der Hardware.
Nur keine direkt verdrahtete Hardware, sondern langsamere.
So viel langsamer ist Microcode aber nicht.
Vielleicht 5..7-mal.
Emulation ist allerdings 30- bis 150-mal langsamer.

Nach 1 Minute gefunden:
|Presented in this paper are the performance and accuracy evaluations of
|eleven transcendental functions found in 64 and 128 bit floating-point formats
|in math libraries on the CRAYY-MP, the IBM 3090E/VF, the Convex C-240, the
|Hewlett Packard 9000/720 and the IBM System/6000.
|Both architecture and algorithms are shown to impact the results.
|Published in: Supercomputing '91:Proceedings of the 1991 ...

Bonita Montero

unread,
Jun 24, 2022, 12:04:58 PM6/24/22
to
Am 24.06.2022 um 16:19 schrieb Helmut Schellong:

>>>> auf meiner TR3990X Zen2-CPU 12 - 60 Takte. Das bisschen Integer
>>>> Bit-Frickelei da oben liegt da sicher ne Größenordnung drunter.

>>> Funktioniert die Bit-Frickelei denn einwandfrei in allen Lagen?

>> Was für eine blöde Verlegenheits-Frage.

> Ohne Tests - das geht gar nicht.

Ich mein wenn man halbwegds den Durchblick hat, dann ist dass offen-
sichtlich, dass so ein extrem Latenz-lastiges FPREM gegen diese hän-
dische Bit-Frickelei nicht anstinken kann.

Bonita Montero

unread,
Jun 24, 2022, 12:08:24 PM6/24/22
to
Am 24.06.2022 um 17:39 schrieb Helmut Schellong:

>> Es rechnet aber heute nahezu keiner mit 80 oder 128 Bit FP.

> Hunderttausende oder Millionen rechnen mit 128-Bit-FP.

Ja, deswegen sind SPARC und PA-RISC tot und die Libraries für
128 Bit FP in Software findest Du garantiert nicht an prominenter
Stelle.

> Microcode arbeitet ja in der Hardware.

Nein, Microcode hat ggf. mehr Möglichkeiten, ist aber Software.
Ich mein der Microcode wird ja beim Initialisieren des Rechners
in die CPU geladen bzw. kann zur Laufzeit noch ersetzt werden.


> Nach 1 Minute gefunden:
> |Presented in this paper are the performance and accuracy evaluations of
> |eleven transcendental functions found in 64 and 128 bit floating-point
> formats
> |in math libraries on the CRAYY-MP, the IBM 3090E/VF, the Convex C-240, the
> |Hewlett Packard 9000/720 and the IBM System/6000.
> |Both architecture and algorithms are shown to impact the results.
> |Published in: Supercomputing '91:Proceedings of the 1991 ...


Äh, bei transzendenten Operationen habe ich dir auf einer aktuellen und
repräsentativen CPU das Gegenteil bewiesen.

Helmut Schellong

unread,
Jun 24, 2022, 12:37:41 PM6/24/22
to
On 06/24/2022 13:19, Bonita Montero wrote:
> Am 24.06.2022 um 10:53 schrieb Helmut Schellong:
>
>>> Es gibt aber keine x87-Funktion die direkt feststellt, ob ein FP-Wert
>>> gerade oder ungerade ist.
>
>> Doch, fprem und fprem1.
>>      remainder = x / 2.0;
>> liefert direkt die Eigenschaft Ungerade|Gerade.
>
> Erstens ist FPEM verglleichsweise langsam. Zweitens hat das Ergebnis

Es ist nicht genau bekannt, wie schnell FPREM bei einem Divisor=2.0 ist.

> zwei mögliche Exponenten anhand derer Du gerade und ungerade unter-
> scheiden kannst (>= 0.0 vs. >= 1.0). D.h. ein wenig Bit-Frickelei
> ist dennoch nötig.

Nein.
Die Feststellung, ob der Rest==1.0 ist, ist simpel:

"fld1 \n\t"
"fcomip %%st(1), %%st(0) \n\t"
"sete %%cl \n\t" //odd


> Ich mein: da kann man doch direkt die schnellere Lösung nehmen.

Die Portabilität durch die Verwendung des Erweiterten Inline-Assemblers
ist wesentlich höher. Schrieb ich bereits.
Die drei Zeilen oben werden gültig bleiben, solange es X86 gibt.
Ich habe auf Pentium-60 70 Takte für fsin/fcos gemessen (16..126 laut Intel).
fprem hat 32 Takte (16..64 laut Intel).

>> Ich und Millionen Andere brauchen das.
>
> Du hast son Sockenschuss, dass ich dir das nicht abnehme.

Ich schrieb bereits, daß Du Dir die Welt zurecht-behauptest.

>>> https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format
>
>> Alle Gleitkommaformate sind prinzipiell gleich.
>
> Bei IEEE-754 und obigem - lies den Link - würde ich eher von
> ähnlich sprechen.

Ähnlich, aber _prinzipiell_ gleich.

>> Homogenität ist in Technik und Wissenschaft absolut wichtig.
>
> An der Stelle haben deine Zwänge absolut keine Vorteile.
>
>> Nein, ich würde verlieren.
>> Ich habe doch schon mehrmals verloren, durch Projektlücken!
>> Habe ich doch geschrieben!
>> Mit meiner Lib verliere ich nicht.
>
> Wer solche Zwänge hat wie Du, der verliert damit überall
> im Leben, nicht nur bei der SW-Entwicklung.

Komischerweise habe ich im Leben mit Software immer gewonnen.
Ansonsten war ich fast immer erfolgreich und anerkannt.

Helmut Schellong

unread,
Jun 24, 2022, 12:45:10 PM6/24/22
to
On 06/24/2022 15:03, Bonita Montero wrote:
> So, ich habe meinen Code noch mehr aufgeblasen, dass der nicht nur
> FSIN gg. sin() vergleicht, sondern noch FTAN gg. tan() sowie FPREM
> [...]
> So Helmut, wie war das nochmal mit 30 mal langsamer ?

Ich kann Deine Resultate nicht prüfen.
Die Meßmethode muß geeignet sein...

Bonita Montero

unread,
Jun 24, 2022, 12:51:04 PM6/24/22
to
Am 24.06.2022 um 18:45 schrieb Helmut Schellong:
> On 06/24/2022 15:03, Bonita Montero wrote:
>> So, ich habe meinen Code noch mehr aufgeblasen, dass der nicht nur
>> FSIN gg. sin() vergleicht, sondern noch FTAN gg. tan() sowie FPREM
>> [...]
>> So Helmut, wie war das nochmal mit 30 mal langsamer ?
>
> Ich kann Deine Resultate nicht prüfen.
> Die Meßmethode muß geeignet sein...

Die Methode ist geeignet für jemand der einen C++20-kompatiblen Compiler
installieren kann.
Dann einfach sowas wie: clang++ -std:c++20 -O2 xxx.cpp
Das hat schon alles deine Korrektheit.

Bonita Montero

unread,
Jun 24, 2022, 1:02:24 PM6/24/22
to
Am 24.06.2022 um 18:38 schrieb Helmut Schellong:

> Es ist nicht genau bekannt, wie schnell FPREM bei einem Divisor=2.0 ist.

Bitte schön, vorsicht heiß, gerade aus dem Ofen gekommen.

#include <iostream>
#include <limits>
#include <cstring>
#include <cstdint>
#include <cfenv>
#include <stdexcept>
#include <cmath>
#include <vector>
#include <random>
#include <chrono>
#include <atomic>

using namespace std;
using namespace chrono;

bool doubleOdd( double d );
bool fpremOdd( double d );

int main()
{
constexpr size_t
N_VALUES = 100,
ROUNDS = 100'000;
vector<double> values( N_VALUES );
mt19937_64 mt;
uniform_real_distribution<double> rndValues( 0.5, 0x1.0p54 - 1.0 );
for( double &v : values )
v = rndValues( mt );
atomic_char aSum;
auto oddBench = [&]<typename OddFn>( OddFn oddFn ) -> double
requires requires( OddFn oddFn ) { { oddFn( 1.0 ) } ->
convertible_to<bool>; }
{
auto start = high_resolution_clock::now();
char sum = 0;
atomic_char aLastSum = 0;
for( size_t r = ROUNDS; r--; )
for( double v : values )
{
int64_t iValue;
memcpy( &iValue, &v, 8 );
iValue ^= aLastSum.load( memory_order_relaxed );
memcpy( &v, &iValue, 8 );
sum += oddFn( v );
aLastSum.store( sum, memory_order_relaxed );
aLastSum.store( 0, memory_order_relaxed );
}
aSum = sum;
return (double)(int64_t)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / ((double)N_VALUES *
ROUNDS);
};
cout << "playing with bits: " << oddBench( doubleOdd ) << endl;
cout << "pure math: " << oddBench( fpremOdd ) << endl;
}

bool doubleOdd( double d )
{
static_assert(sizeof(double) == 8 && numeric_limits<double>::is_iec559,
"double must be 8 bytes and IEEE-754");
uint64_t i, e;
memcpy( &i, &d, 8 );
e = i & 0x7FF0000000000000;
if( e < 0x3FF0000000000000 ) [[unlikely]]
return false;
if( e == 0x3FF0000000000000 ) [[unlikely]]
return true;
if( e > (uint64_t)(0x3FF + 52) << 52 ) [[unlikely]]
{
if( e == 0x7FF ) [[unlikely]]
feraiseexcept( FE_INVALID );
return false;
}
unsigned s = (unsigned)(e >> 52) - 0x3FF;
return i & 0x10000000000000 >> s;
}

bool fpremOdd( double d )
{
return remainder( fabs( d ), 2.0 ) >= 1.0;
}

Ergebnis mit clang 13:
playing with bits: 1.323
pure math: 20.0189

Also: Faktor 22,7.
Is aber natürlich alles fehlerhaft weil Du das nicht überprüfen kannst.

> Nein.
> Die Feststellung, ob der Rest==1.0 ist, ist simpel:
>
>             "fld1 \n\t"
>             "fcomip  %%st(1), %%st(0) \n\t"
>             "sete  %%cl \n\t" //odd

Kann man auch so machen bzw. das ist die geradlinigste Lösung.
Aber ich würde das Ganze auf Integer-Operationen basieren lassen,
die wesentlich effizienter sind.

> Die Portabilität durch die Verwendung des Erweiterten
> Inline-Assemblers ist wesentlich höher. Schrieb ich bereits.

Du machst bei deinem Inline-Assembler Annhamen über die CPU,
somit auch welche über die Datentypen wie double; ich mache
nur letzteres.

> Ich habe auf Pentium-60 70 Takte für fsin/fcos gemessen (16..126 laut
> Intel). fprem hat 32 Takte (16..64 laut Intel).

Hier, _deine_ Quelle:
https://www2.math.uni-wuppertal.de/~fpf/Uebungen/GdR-SS02/opcode_f.html
variations 8087 287 387 486 Pentium
fsin - - 122-771 257-354 16-126 NP

> Ähnlich, aber _prinzipiell_ gleich.

NEIN, prinzipiell gleich sind float und double, zwischen
double und long double gibt es prinzipielle Unterschiede.

> Komischerweise habe ich im Leben mit Software immer gewonnen.

Ja, mangels fähiger Leute nimmt man jeden.

Helmut Schellong

unread,
Jun 24, 2022, 2:01:31 PM6/24/22
to
On 06/24/2022 18:08, Bonita Montero wrote:
> Am 24.06.2022 um 17:39 schrieb Helmut Schellong:
>
>>> Es rechnet aber heute nahezu keiner mit 80 oder 128 Bit FP.
>
>> Hunderttausende oder Millionen rechnen mit 128-Bit-FP.
>
> Ja, deswegen sind SPARC und PA-RISC tot und die Libraries für
> 128 Bit FP in Software findest Du garantiert nicht an prominenter
> Stelle.
>
>> Microcode arbeitet ja in der Hardware.
>
> Nein, Microcode hat ggf. mehr Möglichkeiten, ist aber Software.
> Ich mein der Microcode wird ja beim Initialisieren des Rechners
> in die CPU geladen bzw. kann zur Laufzeit noch ersetzt werden.

Der Microcode arbeitet in der Hardware, innerhalb des CPU-Gehäuses.
Dieses Konzept spart Transistoren im Chip.

>> Nach 1 Minute gefunden:
>> |Presented in this paper are the performance and accuracy evaluations of
>> |eleven transcendental functions found in 64 and 128 bit floating-point formats
>> |in math libraries on the CRAYY-MP, the IBM 3090E/VF, the Convex C-240, the
>> |Hewlett Packard 9000/720 and the IBM System/6000.
>> |Both architecture and algorithms are shown to impact the results.
>> |Published in: Supercomputing '91:Proceedings of the 1991 ...
>
>
> Äh, bei transzendenten Operationen habe ich dir auf einer aktuellen und
> repräsentativen CPU das Gegenteil bewiesen.

Das ist nicht so sicher.
Du kannst wegen ungeeignetem Meßkonzept Zeiten mitgemessen haben, die
eben nicht hätten mitgemessen werden sollen.

Helmut Schellong

unread,
Jun 24, 2022, 2:04:02 PM6/24/22
to
Wenn man Instruktionen mißt, muß ein spezielles Meß-Konzept verwendet werden.
Andernfalls mißt man Mist.

Helmut Schellong

unread,
Jun 24, 2022, 2:39:11 PM6/24/22
to
Natürlich ist es grob fehlerhaft:

fprem berechnet den Gleitkomma-Divisionsrest.
Du setzt dem jedoch die Erkennung von Ungerade/Odd gegenüber.
Das ist stark verfälschend.

Zweitens mußt Du den Taktbedarf der Instruktion fprem messen.
Und zwar _nur_ diesen Taktbedarf, nicht die Takte des Drumherums.

>> Nein.
>> Die Feststellung, ob der Rest==1.0 ist, ist simpel:
>>
>>              "fld1 \n\t"
>>              "fcomip  %%st(1), %%st(0) \n\t"
>>              "sete  %%cl \n\t" //odd
>
> Kann man auch so machen bzw. das ist die geradlinigste Lösung.
> Aber ich würde das Ganze auf Integer-Operationen basieren lassen,
> die wesentlich effizienter sind.

Hatte ich.
Aber ich machte mir Sorgen, weil der Integer-Wertbereich
wesentlich kleiner ist, als der FP-Wertbereich.

>> Die Portabilität durch die Verwendung des Erweiterten
>> Inline-Assemblers ist wesentlich höher. Schrieb ich bereits.
>
> Du machst bei deinem Inline-Assembler Annhamen über die CPU,
> somit auch welche über die Datentypen wie double; ich mache
> nur letzteres.

Ich mache keine Annahmen über die CPU, und auch keine über das long-double-Format.
Ich schreibe einfach nur gültige Instruktionen hin.

>> Ich habe auf Pentium-60 70 Takte für fsin/fcos gemessen (16..126 laut Intel). fprem hat 32 Takte (16..64 laut Intel).
>
> Hier, _deine_ Quelle:
> https://www2.math.uni-wuppertal.de/~fpf/Uebungen/GdR-SS02/opcode_f.html
> variations    8087         287        387      486     Pentium
> fsin           -            -       122-771  257-354   16-126  NP

Das ist eine fremde Quelle, ohne meine Messungen.
Die Takte dort sind aus Intel-Datenbüchern.

Meine Quelle ist: http://www.schellong.de/pent.htm
Gepostet:
06/10/2022 20:24, 06/11/2022 13:12, 06/11/2022 16:28, 06/11/2022 20:58, 06/12/2022 10:05, 06/18/2022 21:29

>> Ähnlich, aber _prinzipiell_ gleich.
>
> NEIN, prinzipiell gleich sind float und double, zwischen
> double und long double gibt es prinzipielle Unterschiede.

Welche?
Es gibt keine prinzipiellen Unterschiede.

>> Komischerweise habe ich im Leben mit Software immer gewonnen.
>
> Ja, mangels fähiger Leute nimmt man jeden.

Man hat mir exzellente Zeugnisse ausgestellt.

Du behauptest erneut.
Du hast Langeweile...

Bonita Montero

unread,
Jun 24, 2022, 3:32:02 PM6/24/22
to
Am 24.06.2022 um 20:04 schrieb Helmut Schellong:
> On 06/24/2022 18:51, Bonita Montero wrote:
>> Am 24.06.2022 um 18:45 schrieb Helmut Schellong:
>>> On 06/24/2022 15:03, Bonita Montero wrote:
>>>> So, ich habe meinen Code noch mehr aufgeblasen, dass der nicht nur
>>>> FSIN gg. sin() vergleicht, sondern noch FTAN gg. tan() sowie FPREM
>>>> [...]
>>>> So Helmut, wie war das nochmal mit 30 mal langsamer ?
>>>
>>> Ich kann Deine Resultate nicht prüfen.
>>> Die Meßmethode muß geeignet sein...
>>
>> Die Methode ist geeignet für jemand der einen C++20-kompatiblen Compiler
>> installieren kann.
>> Dann einfach sowas wie: clang++ -std:c++20 -O2 xxx.cpp
>> Das hat schon alles deine Korrektheit.
>
> Wenn man Instruktionen mißt, muß ein spezielles Meß-Konzept verwendet
> werden.
> Andernfalls mißt man Mist.

Das ist für alle meine Benchmarks korrekt,
wie Du dem Source entnehmen kannst.

Bonita Montero

unread,
Jun 24, 2022, 3:39:11 PM6/24/22
to
Am 24.06.2022 um 20:39 schrieb Helmut Schellong:

> fprem berechnet den Gleitkomma-Divisionsrest.
> Du setzt dem jedoch die Erkennung von Ungerade/Odd gegenüber.

Einen FPREM-Benchmark hatte ich ja bereits geliefert und der
brachte ähnliche Ergebnisse.
Ich hab das nur nochmal einen Schritt weitergedacht und daraus
eben wie sich auch im weiteren Verlauf der Diskussion ergab
das von dir angedachte Even / Odd mit dem Schwellwert geschrieben.,

> Zweitens mußt Du den Taktbedarf der Instruktion fprem messen.
> Und zwar _nur_ diesen Taktbedarf, nicht die Takte des Drumherums.

Äh, das ist eine so gigantisch Latenz-Lastige Instruktion, das das
Drumherum quasi nicht zählt. Zumal die CPU während der langen Laufzeit
von FPREM schon zig Instruktionen im Voraus holt und ausführt, dass
die FPREMs sich im Instruction Scheduler auf die Füße treten, d.h.
der Rest so ziemlich egal wird.

> Hatte ich.
> Aber ich machte mir Sorgen, weil der Integer-Wertbereich
> wesentlich kleiner ist, als der FP-Wertbereich.

Äh, ich will nix in Integer konvertieren, sondern das ganze Bit-Muster
aus dem SSE-Register 1:1 in ein 64 Bit Register übertragen, dann den
Exponent maskieren und dann einen Vergleich darauf machen - hat je
einen Takt Latenz und Integer-Operationen können mit mehr instruction
-level parallelism ausgeführt werden als FP-Operationen.

>>> Die Portabilität durch die Verwendung des Erweiterten
>>> Inline-Assemblers ist wesentlich höher. Schrieb ich bereits.
>>
>> Du machst bei deinem Inline-Assembler Annhamen über die CPU,
>> somit auch welche über die Datentypen wie double; ich mache
>> nur letzteres.

> Ich mache keine Annahmen über die CPU, und auch keine über das
> long-double-Format.

Ne, mit Assembler macht man natüüüürlich keine Annahmen über die CPU-

> Das ist eine fremde Quelle, ohne meine Messungen.

Darauf hast Du dich aber selbst schon mal bezogen.

> Die Takte dort sind aus Intel-Datenbüchern.

Die Intel Datenbücher zum Pentium 1 enthalten keine Takt-Angaben.

>> NEIN, prinzipiell gleich sind float und double, zwischen
>> double und long double gibt es prinzipielle Unterschiede.

> Welche?
> Es gibt keine prinzipiellen Unterschiede.

Kannst Du Blödmann dir nicht einfach mal die Tabelle anschauen ?

> Man hat mir exzellente Zeugnisse ausgestellt.

Ja, solche Leute kenn ich auch ein paar.

Bonita Montero

unread,
Jun 24, 2022, 3:42:46 PM6/24/22
to
Am 24.06.2022 um 20:01 schrieb Helmut Schellong:

> Der Microcode arbeitet in der Hardware, innerhalb des CPU-Gehäuses.
> Dieses Konzept spart Transistoren im Chip.

Moderne x86er sind intern RISC-CPUs deren RISC-Instruktionen die ganze
Semantik von x86 indirekt abbilden. Der Microcode besteht darüber hinaus
aus zusätzlichen Instruktionen die nicht durch x86 zugänglich sind (es
hat das aber jemand mal für AMD K10 entschlüsselt und auf irgendeinem
Idioten-Kongess veröffentlicht).

> Das ist nicht so sicher.
> Du kannst wegen ungeeignetem Meßkonzept Zeiten mitgemessen haben,
> die eben nicht hätten mitgemessen werden sollen.

Bitte erzähl keinen Quatsch, sondern lies meinen Code und sag mir bitte,
was ich falsch gemacht haben soll.
Ich mein transzendente Operationen sind nicht ganz unwichtig, und wenn
die zigmal schnneller in Hardware realisierbar wären, dann wäre Intel
sicher nicht so doof gewesen, die in SSE und AVX wegzulassen.

Du bist echt so ein ulta-verbohrter Nerd-Opa.

Helmut Schellong

unread,
Jun 24, 2022, 9:55:04 PM6/24/22
to
On 06/24/2022 21:39, Bonita Montero wrote:
> Am 24.06.2022 um 20:39 schrieb Helmut Schellong:
>
>> fprem berechnet den Gleitkomma-Divisionsrest.
>> Du setzt dem jedoch die Erkennung von Ungerade/Odd gegenüber.
>
> Einen FPREM-Benchmark hatte ich ja bereits geliefert und der
> brachte ähnliche Ergebnisse.
> Ich hab das nur nochmal einen Schritt weitergedacht und daraus
> eben wie sich auch im weiteren Verlauf der Diskussion ergab
> das von dir angedachte Even / Odd mit dem Schwellwert geschrieben.,
>
>> Zweitens mußt Du den Taktbedarf der Instruktion fprem messen.
>> Und zwar _nur_ diesen Taktbedarf, nicht die Takte des Drumherums.
>
> Äh, das ist eine so gigantisch Latenz-Lastige Instruktion, das das
> Drumherum quasi nicht zählt. Zumal die CPU während der langen Laufzeit
> von FPREM schon zig Instruktionen im Voraus holt und ausführt, dass
> die FPREMs sich im Instruction Scheduler auf die Füße treten, d.h.
> der Rest so ziemlich egal wird.

Ich messe jedenfalls mit einem Differenz-Verfahren, das auch im
Sub-Nano-Sekunden-Bereich genügend genaue Ergebnisse produziert.

>> Hatte ich.
>> Aber ich machte mir Sorgen, weil der Integer-Wertbereich
>> wesentlich kleiner ist, als der FP-Wertbereich.
>
> Äh, ich will nix in Integer konvertieren, sondern das ganze Bit-Muster
> aus dem SSE-Register 1:1 in ein 64 Bit Register übertragen, dann den
> Exponent maskieren und dann einen Vergleich darauf machen - hat je
> einen Takt Latenz und Integer-Operationen können mit mehr instruction
> -level parallelism ausgeführt werden als FP-Operationen.

Ich kümmere mich um solche Details gar nicht, sondern der Compiler
macht das stets passend automatisch, im Rahmen des Erweiterten Inline-Assembler.

Nicht-FPU-Instruktionen können sich quasi in FPU-Instruktionen verstecken.
Sie laufen parallel zu den FPU-Instruktionen.
Mitunter müssen sie sogar synchronisiert werden.

>>>> Die Portabilität durch die Verwendung des Erweiterten
>>>> Inline-Assemblers ist wesentlich höher. Schrieb ich bereits.
>>>
>>> Du machst bei deinem Inline-Assembler Annhamen über die CPU,
>>> somit auch welche über die Datentypen wie double; ich mache
>>> nur letzteres.
>
>> Ich mache keine Annahmen über die CPU, und auch keine über das long-double-Format.
>
> Ne, mit Assembler macht man natüüüürlich keine Annahmen über die CPU-

Richtig, mit Assembler werden keine Annahmen über die CPU gemacht.
Ich schreibe einfach nur gültige Instruktionen hin.
Das ist genau so wie in C, wo ich auch keine Annahmen mache.
Assembler ist eine Programmiersprache, prinzipiell wie C.
Man muß eben die Regeln/Vorgaben der jeweiligen Sprache beachten.

>> Das ist eine fremde Quelle, ohne meine Messungen.
>
> Darauf hast Du dich aber selbst schon mal bezogen.

Ja, ergänzend, als weiterer Beleg.

>> Die Takte dort sind aus Intel-Datenbüchern.
>
> Die Intel Datenbücher zum Pentium 1 enthalten keine Takt-Angaben.

Intel bietet viele Datenbücher zu jeweiligen Produkten an.
Beispielsweise Developer-Handbücher und Optimize-Handbücher.

Die Takte zwischen {...} sind aus Datenbüchern; sie sind genau übereinstimmend.
Wenn bei der Hochschul-Quelle 16-126 angegeben ist und bei mir:
fsin, fcos 70 {16-126} 241(193-279)2 122-772/+76
stammen diese Angaben offenbar aus einem Intel-Datenbuch.

In meiner Webseite gebe ich an:
|"{ ... } : Abweichende Werte aus Intel-Handbuch [1]"
http://www.schellong.de/pent.htm

>>> NEIN, prinzipiell gleich sind float und double, zwischen
>>> double und long double gibt es prinzipielle Unterschiede.
>
>> Welche?
>> Es gibt keine prinzipiellen Unterschiede.
>
> Kannst Du Blödmann dir nicht einfach mal die Tabelle anschauen ?

Nein, weil Du stets fast alles weg-löschst, worauf Du antwortest.
Hier haben wir sie:
https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format
https://en.wikipedia.org/wiki/Double-precision_floating-point_format#Double-precision_examples

Ich sehe da keine _prinzipiellen_ Unterschiede.

Helmut Schellong

unread,
Jun 24, 2022, 11:12:18 PM6/24/22
to
On 06/24/2022 21:43, Bonita Montero wrote:
> Am 24.06.2022 um 20:01 schrieb Helmut Schellong:
>
>> Der Microcode arbeitet in der Hardware, innerhalb des CPU-Gehäuses.
>> Dieses Konzept spart Transistoren im Chip.
>
> Moderne x86er sind intern RISC-CPUs deren RISC-Instruktionen die ganze
> Semantik von x86 indirekt abbilden. Der Microcode besteht darüber hinaus
> aus zusätzlichen Instruktionen die nicht durch x86 zugänglich sind (es
> hat das aber jemand mal für AMD K10 entschlüsselt und auf irgendeinem
> Idioten-Kongess veröffentlicht).

Na und?
Trotzdem wird der Microcode innerhalb des CPU-Gehäuses abgearbeitet.
Also innerhalb der Hardware-Komponente.

Es findet hier ein Mißbrauch von 'RISC' statt.
Diese Abkürzung sagt aus, daß es sich um einen reduzierten Instruktionssatz handelt.
Dies ist aber nicht der Fall - es ist nach wie vor CISC.

Man hat nämlich den Pentium im Lauf der Zeit Zug um Zug beschleunigt, indem
Microcode-Instruktionen in direkt-verdrahtete umgewandelt wurden.
Zu Beginn brauchten shift und rotate 4..9 Takte und waren nicht parallelisierbar.
Das hat sich inzwischen geändert.
Manche Microcontroller und DSPs multiplizieren z.B. in 1,6 Takten.
Das ist dann /direkt-verdrahtet/.

>> Das ist nicht so sicher.
>> Du kannst wegen ungeeignetem Meßkonzept Zeiten mitgemessen haben,
>> die eben nicht hätten mitgemessen werden sollen.
>
> Bitte erzähl keinen Quatsch, sondern lies meinen Code und sag mir bitte,
> was ich falsch gemacht haben soll.

i+i+t - (i+t) = i

n*i+n(i+t) - n(i+t) = n*i

Das ist ein mathematischer Ansatz, den ich in den 1980ern erfand.
Ich habe einen Code gemessen, mit einer interessierenden Instruktion 2-mal darin.
Danach einen mit einer solchen Instruktion 1-mal, und diese zweite Gesamtzeit subtrahiert.
Und die Zeit t verschwindet.
Im C-Code habe ich dann volatile verwendet.

Das ist eine Eliminierung, prinzipiell wie beim Dual-Slope-Verfahren.

> Ich mein transzendente Operationen sind nicht ganz unwichtig, und wenn
> die zigmal schnneller in Hardware realisierbar wären, dann wäre Intel
> sicher nicht so doof gewesen, die in SSE und AVX wegzulassen.

Sie haben sie dort weggelassen, denn sie haben ja die FPU.

> Du bist echt so ein ulta-verbohrter Nerd-Opa.

Ich bin ein alter Zausel, ein Sonderling.

Bonita Montero

unread,
Jun 25, 2022, 12:16:38 AM6/25/22
to
Am 25.06.2022 um 05:12 schrieb Helmut Schellong:

>> Moderne x86er sind intern RISC-CPUs deren RISC-Instruktionen die ganze
>> Semantik von x86 indirekt abbilden. Der Microcode besteht darüber hinaus
>> aus zusätzlichen Instruktionen die nicht durch x86 zugänglich sind (es
>> hat das aber jemand mal für AMD K10 entschlüsselt und auf irgendeinem
>> Idioten-Kongess veröffentlicht).

> Na und?
> Trotzdem wird der Microcode innerhalb des CPU-Gehäuses abgearbeitet.
> Also innerhalb der Hardware-Komponente.

Es ging darum, dass die Software ist; das ist die eben nicht.

> Es findet hier ein Mißbrauch von 'RISC' statt.

Was hat das mit obiger Fragestellung zu tun ?

> Man hat nämlich den Pentium im Lauf der Zeit Zug um Zug beschleunigt,
> indem Microcode-Instruktionen in direkt-verdrahtete umgewandelt wurden.

Das ist in Teilen bei vielen x86-Generationen passiert.

> Zu Beginn brauchten shift und rotate 4..9 Takte und waren nicht

Das heißt nicht, dass die vorher microcoded waren, sondern
i.d.R. sicher einfach nur iterativ getaktete Schaltungen waren.

>> Bitte erzähl keinen Quatsch, sondern lies meinen Code und sag mir bitte,
>> was ich falsch gemacht haben soll.

> i+i+t - (i+t) = i
>
> n*i+n(i+t) - n(i+t) = n*i
>
> Das ist ein mathematischer Ansatz, den ich in den 1980ern erfand.
> Ich habe einen Code gemessen, mit einer interessierenden Instruktion
> 2-mal darin.
> Danach einen mit einer solchen Instruktion 1-mal, und diese zweite
> Gesamtzeit subtrahiert.
> Und die Zeit t verschwindet.
> Im C-Code habe ich dann volatile verwendet.

Wo ist da jetzt bitte der Fehler in meinem Code ?


> Sie haben sie dort weggelassen, denn sie haben ja die FPU.

Die wird heute in den Runtimes nicht mehr genutzt weil das händisch
emuliert schneller geht.

>> Du bist echt so ein ulta-verbohrter Nerd-Opa.

> Ich bin ein alter Zausel, ein Sonderling.

Ich find's schlimm, aber wenn Du das annehmen kannst,
dann ist ja alles o.k.

Bonita Montero

unread,
Jun 25, 2022, 1:52:10 AM6/25/22
to
Am 25.06.2022 um 03:55 schrieb Helmut Schellong:

> Ich messe jedenfalls mit einem Differenz-Verfahren, das auch im
> Sub-Nano-Sekunden-Bereich genügend genaue Ergebnisse produziert.

Du weißt doch nichtmal, wie man korrekt Latenz oder Durchsatz
misst. Ich schon.

> Nicht-FPU-Instruktionen können sich quasi in FPU-Instruktionen verstecken.

Höchstens im Microcode, und das auch recht selten.

> Richtig, mit Assembler werden keine Annahmen über die CPU gemacht.

Mit wem red ich hier ?

> Beispielsweise Developer-Handbücher und Optimize-Handbücher.

Du kannst alle möglichen Uralt-Handbücher von Intel bis zum 4004
eingescannt im Netz finden indem Du "<CPU-Name> Intel doctype:pdf"
suchst. Also such mir mal irgendwelche Optimierungs-Handbücher in
denen angeblich Intruktions-Laufzeiten stehen.
Ich bin nämlich ganz doof und finde da nix.

> Die Takte zwischen {...} sind aus Datenbüchern; sie sind genau
> übereinstimmend.

Diese Angaben hat Intel nie gemacht und macht die heute auch nicht.

> Nein, weil Du stets fast alles weg-löschst, worauf Du antwortest.
> Hier haben wir sie:
> https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format
> https://en.wikipedia.org/wiki/Double-precision_floating-point_format#Double-precision_examples
> Ich sehe da keine _prinzipiellen_ Unterschiede.

* Es gibt keine Pseudo-Denormalen bei IEEE-754.
* Es gibt kein Pseudo-Infinity bei IEEE-754.
* Es gibt keine zwei Varianten von Pseudo-NaNs bei IEEE-754.
* Es gibt keine spezielle Codiereung für Indefinites bei IEEE-754.
* Es gibt keine unnormalen Zahlen bei IEEE-754 weil vorne immer
bis auf Denormale immer ne 1 steht.

Ok, keine prinzipiellen Unterschiede, seh ich voll ein. ;-)


Ich hab mir gerade nochmal die Mühe gemacht, FPREM mit 2.0 als Dividend
zu benchen, und zwar so, dass ich nicht den Durchsatz mit überlappenden
FPREMs messe, sondern die absolute Latenz bzw. Laufzeit von FPREM. Dazu
muss man die Operanden des nächsten Laufs vom Ergebnis des vorherigen
Laufs abhängig machen um die out of order Ausführung größtenteils
auszuhebeln.

#include <iostream>
#include <vector>
#include <random>
#include <chrono>

using namespace std;
using namespace chrono;

void fpremBench( double *values, size_t nValues, size_t nRounds );

int main()
{
constexpr size_t
N_VALUES = 100,
ROUNDS = 1'000'000;
vector<double> values( N_VALUES );
mt19937_64 mt;
uniform_real_distribution<double> intFloats( 0.0, 0x1.0p53 - 1.0 );
for( double &v : values )
v = intFloats( mt );
double *data = values.data();
auto start = high_resolution_clock::now();
fpremBench( data, N_VALUES, ROUNDS );
double ns = (double)(int64_t)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / ((double)N_VALUES *
ROUNDS);
cout << ns << endl;
}


PUBLIC ?fpremBench@@YAXPEAN_K1@Z

_DATA SEGMENT
TWO DQ 04000000000000000r
_DATA ENDS

_TEXT SEGMENT
; void fpremBench( double *values, size_t nValues, size_t nRounds );
; rcx = values
; rdx = nValues
; r8 = nRounds
?fpremBench@@YAXPEAN_K1@Z PROC
test rdx, rdx
jz byeBye
test r8, r8
jz byeBye
fld TWO
fldz
outer:
xor rax, rax
inner:
fld qword ptr [rcx + rax * 8]
faddp
fprem
fld st
fsubp
add rax, 1
cmp rax, rdx
jb inner
sub r8, 1
jnz outer
fstp st
fstp st
byeBye:
ret
?fpremBench@@YAXPEAN_K1@Z ENDP
_TEXT ENDS

END

Wie Du siehst sind da noch ein paar kleine Instruktionen, die die
Schleife ein wenig länger machen. Der ganze Schleifen-Index Quark
in Integer-Code wird größtenteils OoO-parallel ausgeführt und hat
praktisch keinen Anteil an der Rechenzeit.

Ergebnis in Nanosekunden: 21.809

Also ein wenig über dem bisherigen Ergebnis weil da noch anderer
serialisierender Code mit drin steckt. Rechne ich da mal 2ns dafür
ab, dann bin ich auf meiner CPU (TR3990X, 4,3GHz wenn nur ein Kern
rechnet) bei 85 Takten pro FPREM.

Ich mein eigentlich muss man da nix messen weil das von vorneherein
klar ist, aber für dich ist das wohl nötig.

Bonita Montero

unread,
Jun 25, 2022, 3:44:12 AM6/25/22
to
Am 25.06.2022 um 07:52 schrieb Bonita Montero:

> ...
> inner:
>     fld     qword ptr [rcx + rax * 8]
>     faddp
>     fprem
>     fld     st
>     fsubp
>     add     rax, 1
>     cmp     rax, rdx
>     jb      inner
>     sub     r8, 1
>     jnz     outer
>     fstp    st
>     fstp    st


Ich hab mir gerade mal überlegt, was denn passieren würde wenn
ich die Teile die die Schleife OoO-linearisieren, dass ich denn
wirklich auch die Latenz messen kann, weglasse damit ich im End-
effekt nur noch den reinen Troughput von FPMOD mit 2.0 als Divi-
dend messen kann. Dann sieht das Ganze nämlich so aus:

inner:
fld qword ptr [rcx + rax * 8]
fprem
fstp st
add rax, 1
cmp rax, rdx
jb inner
sub r8, 1
jnz outer
fstp st

Die Laufzeit obiger Schleife wird dann so gut wie zu 100% rein durch
das FPREM bestimmt bzw. alle anderen Instruktionen werden durch die
Latenz des FPREMs komplett verdeckt und OoO-parallel ausgeführt.
Bei obiger Schleife kommt dann auf meine CPU bei einem belasteten
Thread ziemlich genau 3,5ns raus, also fast exakt 15 Takte für den
Throughput. Das ist sehr nah dran an dem auf agner.org genannten
minimalen Timing, das aber auch in die Größenordnungen eines
Throughputs von 50 Taktgen gehen kann. D.h. weil die 2.0 wohl so
eine kleine Spanne ihrer signifinanten Bit(s) hat liegt der hier
wohl am unteren Ende.
D.h. die restlichen 70 Takte Laufzeit werden durch Überlappung in
meiner Schleife gar nicht mehr sichtbar. Ich mein: nicht, dass mir
was an diesem x87-Käse liegen würde, aber das find ich schon enorm.

Helmut Schellong

unread,
Jun 25, 2022, 10:01:36 AM6/25/22
to
On 06/25/2022 06:17, Bonita Montero wrote:
> Am 25.06.2022 um 05:12 schrieb Helmut Schellong:
>
>>> Moderne x86er sind intern RISC-CPUs deren RISC-Instruktionen die ganze
>>> Semantik von x86 indirekt abbilden. Der Microcode besteht darüber hinaus
>>> aus zusätzlichen Instruktionen die nicht durch x86 zugänglich sind (es
>>> hat das aber jemand mal für AMD K10 entschlüsselt und auf irgendeinem
>>> Idioten-Kongess veröffentlicht).
>
>> Man hat nämlich den Pentium im Lauf der Zeit Zug um Zug beschleunigt,
>> indem Microcode-Instruktionen in direkt-verdrahtete umgewandelt wurden.
>
> Das ist in Teilen bei vielen x86-Generationen passiert.
>
>> Zu Beginn brauchten shift und rotate 4..9 Takte und waren nicht
>
> Das heißt nicht, dass die vorher microcoded waren, sondern
> i.d.R. sicher einfach nur iterativ getaktete Schaltungen waren.

Ich bin kein Experte für digitale Chips.
Aber ich kenne im digitalen Bereich 'Schaltwerke', die von einer Art
Code gesteuert werden.
Und ich kenne direkte Verdrahtung mittels Logik-Gattern und Latches.

>>> Bitte erzähl keinen Quatsch, sondern lies meinen Code und sag mir bitte,
>>> was ich falsch gemacht haben soll.
>
>> i+i+t - (i+t) = i
>>
>> n*i+n(i+t) - n(i+t) = n*i
>>
>> Das ist ein mathematischer Ansatz, den ich in den 1980ern erfand.
>> Ich habe einen Code gemessen, mit einer interessierenden Instruktion 2-mal darin.
>> Danach einen mit einer solchen Instruktion 1-mal, und diese zweite Gesamtzeit subtrahiert.
>> Und die Zeit t verschwindet.
>> Im C-Code habe ich dann volatile verwendet.
>
> Wo ist da jetzt bitte der Fehler in meinem Code ?

Dein Code folgt überhaupt gar nicht diesem oder einem ähnlichen Konzept!
Du mißt Mist, und scheinst das auch noch zu verteidigen.
Als Entwicklungsingenieur wärst Du untauglich.
Du erkennst, wie es scheint, nicht die einfachsten Ansätze.

>> Sie haben sie dort weggelassen, denn sie haben ja die FPU.
>
> Die wird heute in den Runtimes nicht mehr genutzt weil das händisch
> emuliert schneller geht.

In ganz bestimmten Runtimes, die nicht jeder hat, wird es eventuell nicht genutzt.
Ich werde mir jedenfalls kein MSVC oder so kaufen.

Bonita Montero

unread,
Jun 25, 2022, 11:18:33 AM6/25/22
to
Am 25.06.2022 um 16:02 schrieb Helmut Schellong:

> Ich bin kein Experte für digitale Chips.
> Aber ich kenne im digitalen Bereich 'Schaltwerke', die von einer Art
> Code gesteuert werden.
> Und ich kenne direkte Verdrahtung mittels Logik-Gattern und Latches.

Wie dem auch sei, wenn ich etwa ein Rechenwerk für's Multiplizieren
habe, dann spart das nicht viel ein, die Iterationen in Microcode
zu machem.

> Dein Code folgt überhaupt gar nicht diesem oder einem ähnlichen Konzept!

Der löst das disktuierte Problem, herauszufinden ob ein double-Wert
ungerade ist, und das so schnell es eben geht.

> Du mißt Mist, und scheinst das auch noch zu verteidigen.

Dann zeig anhand meines Codes was ich verkehrt mache.

> Als Entwicklungsingenieur wärst Du untauglich.

Du bist echt so ein Frickler mit eingeschränktem Horizont,
das kanns Du daher nicht wirklich glaubwürdig rüberbringen.

> In ganz bestimmten Runtimes, die nicht jeder hat, wird es eventuell
> nicht genutzt.

Sobald eine SSE- oder AVX-FPU da ist wird es immer genutzt.

> Ich werde mir jedenfalls kein MSVC oder so kaufen.

Obiges gilt auch für die glibc, udn die implemementiert die meisten
transzendenten Operationen noch ein wenig effizienter.
Es wäre einfach vom Performance-Standpunkt her unvernünftig, das noch
mit der x87-FPU zu lösen.

Helmut Schellong

unread,
Jun 25, 2022, 1:20:19 PM6/25/22
to
On 06/25/2022 07:52, Bonita Montero wrote:
> Am 25.06.2022 um 03:55 schrieb Helmut Schellong:
>
>> Ich messe jedenfalls mit einem Differenz-Verfahren, das auch im
>> Sub-Nano-Sekunden-Bereich genügend genaue Ergebnisse produziert.
>
> Du weißt doch nichtmal, wie man korrekt Latenz oder Durchsatz
> misst. Ich schon.

Woher willst Du das wissen?
Erneut eine platte Behauptung.
Siehe unten.

>> Nicht-FPU-Instruktionen können sich quasi in FPU-Instruktionen verstecken.
>
> Höchstens im Microcode, und das auch recht selten.

Du hast offenbar nie Optimierungs-Handbücher von Intel gelesen.

>> Beispielsweise Developer-Handbücher und Optimize-Handbücher.
>
> Du kannst alle möglichen Uralt-Handbücher von Intel bis zum 4004
> eingescannt im Netz finden indem Du "<CPU-Name> Intel doctype:pdf"
> suchst. Also such mir mal irgendwelche Optimierungs-Handbücher in
> denen angeblich Intruktions-Laufzeiten stehen.
> Ich bin nämlich ganz doof und finde da nix.
>
>> Die Takte zwischen {...} sind aus Datenbüchern; sie sind genau übereinstimmend.
>
> Diese Angaben hat Intel nie gemacht und macht die heute auch nicht.

Und woher stammen genau übereinstimmende Angaben wie '16-126' in der
Hochschulquelle als auch in http://www.schellong.de/pent.htm ?

http://www.schellong.de/img/div/ia32.jpg

Ich habe schon vor langer, langer Zeit Definitionen zu Latency und Throughput gelesen.
Ebenso sehe ich seit langer Zeit Werte-Tabellen dazu in Intel-Handbüchern.
(In neueren/neuesten nicht mehr; dafür .csv-Dateien mit spärlichem Inhalt.)
Dafür habe ich aus anderer Quelle Clock-Tabellen zu Instruktionen
von etwa 40 verschiedenen CPUs, bis 11. Generation.

FDIV und FSQRT haben inzwischen nur noch ~16 Takte Latency.
FDIV 5 und FMUL 2 Takte Throughput.
Viele FXXX haben nur noch 1..2 Takte Throughput, teilweise 0..½.

>> Nein, weil Du stets fast alles weg-löschst, worauf Du antwortest.
>> Hier haben wir sie:
>> https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format https://en.wikipedia.org/wiki/Double-precision_floating-point_format#Double-precision_examples Ich sehe da keine _prinzipiellen_ Unterschiede.
>
> * Es gibt keine Pseudo-Denormalen bei IEEE-754.
> * Es gibt kein Pseudo-Infinity bei IEEE-754.
> * Es gibt keine zwei Varianten von Pseudo-NaNs bei IEEE-754.
> * Es gibt keine spezielle Codiereung für Indefinites bei IEEE-754.
> * Es gibt keine unnormalen Zahlen bei IEEE-754 weil vorne immer
>   bis auf Denormale immer ne 1 steht.
>
> Ok, keine prinzipiellen Unterschiede, seh ich voll ein. ;-)

Richtig, das sind keine prinzipiellen Unterschiede in den Gleitkomma-Formaten.
Das sind feine Details, Peanuts.

Die fxam-Instruktion zeigt nur an:
case 0: str= "Unsupported"; break;
case 1: str= "NaN"; break;
case 2: str= "Normal"; break;
case 3: str= "Infinity"; break;
case 4: str= "Zero"; break;
case 5: str= "Empty"; break;
case 6: str= "Denormal"; break;

> Ich hab mir gerade nochmal die Mühe gemacht, FPREM  mit 2.0 als Dividend
> zu benchen, und zwar so, dass ich nicht den Durchsatz mit überlappenden
[...]
> Ergebnis in Nanosekunden: 21.809
>
> Also ein wenig über dem bisherigen Ergebnis weil da noch anderer
> serialisierender Code mit drin steckt. Rechne ich da mal 2ns dafür
> ab, dann bin ich auf meiner CPU (TR3990X, 4,3GHz wenn nur ein Kern
> rechnet) bei 85 Takten pro FPREM.
>
> Ich mein eigentlich muss man da nix messen weil das von vorneherein
> klar ist, aber für dich ist das wohl nötig.

Ich habe 1994 32 Takte Latency für FPREM im Pentium-60 gemessen.
Inzwischen sind 26..30 angegeben/gemessen. Throughput==17.

Helmut Schellong

unread,
Jun 25, 2022, 1:31:28 PM6/25/22
to
On 06/25/2022 09:44, Bonita Montero wrote:
> Am 25.06.2022 um 07:52 schrieb Bonita Montero:
>
> > ...
[...]

> Die Laufzeit obiger Schleife wird dann so gut wie zu 100% rein durch
> das FPREM bestimmt bzw. alle anderen Instruktionen werden durch die
> Latenz des FPREMs komplett verdeckt und OoO-parallel ausgeführt.
> Bei obiger Schleife kommt dann auf meine CPU bei einem belasteten
> Thread ziemlich genau 3,5ns raus, also fast exakt 15 Takte für den
> Throughput. Das ist sehr nah dran an dem auf agner.org genannten
> minimalen Timing, das aber auch in die Größenordnungen eines
> Throughputs von 50 Taktgen gehen kann. D.h. weil die 2.0 wohl so
> eine kleine Spanne ihrer signifinanten Bit(s) hat liegt der hier
> wohl am unteren Ende.

Ja, deshalb habe ich meine Lösung mit FIST verworfen und FPREM genommen.
Immerhin ist 2.0 intern eine Ganzzahl, wodurch minimale Taktwerte entstehen.

Innerhalb von pow87l() wird fprem ohnehin _sehr selten_ angelaufen.
Das kommt als Grund noch dazu.

Die Tabellen von Agner habe ich mir letztes Jahr besorgt.

Helmut Schellong

unread,
Jun 25, 2022, 1:43:02 PM6/25/22
to
On 06/25/2022 17:19, Bonita Montero wrote:
> Am 25.06.2022 um 16:02 schrieb Helmut Schellong:
>
>> Ich bin kein Experte für digitale Chips.
>> Aber ich kenne im digitalen Bereich 'Schaltwerke', die von einer Art
>> Code gesteuert werden.
>> Und ich kenne direkte Verdrahtung mittels Logik-Gattern und Latches.
>
> Wie dem auch sei, wenn ich etwa ein Rechenwerk für's Multiplizieren
> habe, dann spart das nicht viel ein, die Iterationen in Microcode
> zu machem.
>
>> Dein Code folgt überhaupt gar nicht diesem oder einem ähnlichen Konzept!
>
> Der löst das disktuierte Problem, herauszufinden ob ein double-Wert
> ungerade ist, und das so schnell es eben geht.
>
>> Du mißt Mist, und scheinst das auch noch zu verteidigen.
>
> Dann zeig anhand meines Codes was ich verkehrt mache.

Das sage ich nun zum Dritten Mal:
Dein Code folgt überhaupt gar nicht diesem oder einem ähnlichen Meß-Konzept!
Du mißt auf sehr ungeeignete Weise! - Ausgerechnet bei Instruktionen!

>> Als Entwicklungsingenieur wärst Du untauglich.
>
> Du bist echt so ein Frickler mit eingeschränktem Horizont,
> das kanns Du daher nicht wirklich glaubwürdig rüberbringen.

Ich habe vorstehend etwas zum Dritten Mal geschrieben, weil Du es
bisher nicht verstanden hast.

>> In ganz bestimmten Runtimes, die nicht jeder hat, wird es eventuell nicht genutzt.
>
> Sobald eine SSE- oder AVX-FPU da ist wird es immer genutzt.
>
>> Ich werde mir jedenfalls kein MSVC oder so kaufen.
>
> Obiges gilt auch für die glibc, udn die implemementiert die meisten
> transzendenten Operationen noch ein wenig effizienter.
> Es wäre einfach vom Performance-Standpunkt her unvernünftig, das noch
> mit der x87-FPU zu lösen.

Es geht nicht nur um Performance, sondern beispielsweise auch
um Homogenität und Vollständigkeit, und sehr geringen Code-Umfang.
Die Lib mit 59 Funktionen hat nur 2700 Byte.

Bonita Montero

unread,
Jun 25, 2022, 2:08:23 PM6/25/22
to
Am 25.06.2022 um 19:31 schrieb Helmut Schellong:

>> Die Laufzeit obiger Schleife wird dann so gut wie zu 100% rein durch
>> das FPREM bestimmt bzw. alle anderen Instruktionen werden durch die
>> Latenz des FPREMs komplett verdeckt und OoO-parallel ausgeführt.
>> Bei obiger Schleife kommt dann auf meine CPU bei einem belasteten
>> Thread ziemlich genau 3,5ns raus, also fast exakt 15 Takte für den
>> Throughput. Das ist sehr nah dran an dem auf agner.org genannten
>> minimalen Timing, das aber auch in die Größenordnungen eines
>> Throughputs von 50 Taktgen gehen kann. D.h. weil die 2.0 wohl so
>> eine kleine Spanne ihrer signifinanten Bit(s) hat liegt der hier
>> wohl am unteren Ende.

> Ja, deshalb habe ich meine Lösung mit FIST verworfen und FPREM genommen.

Äh, was hat das genau mit meiner Diskussion um Latenz und Laufzeit
von FPREM zu tun ?
Grundsätzlich find ich aber eine Lösung mit FIST einigermaßen effizient.
Ich mein man hat 53 Bit Mantisse und wenn die Werte so groß sind, dass
die nicht mehr in das 64 Bit Integer passen, dann liegt das "virtuelle"
niederwertigste Bit das über gerade und ungerade entscheidet eben rechts
von der Mantisse und ist immer Null. D.h. man könnte erstmal schauen,
ob die Konvertierung gen Integer nicht den magischen Wert 1 << 63 gibt
und somit gegen einen Überlauf testen - dann ist der Wert so groß, dass
er sowieso gerade ist, zumindest wenn ich kein Inf oder NaN habe, und
wenn eben nicht, dann teste ich auf das niederwertigste Bit in einem
Integer-Register; das kriegst auch Du schnell hin.
Ich nehm mal stark an, dass das gar nicht so viel langsamer ist als
meine Lösung, aber eben vom Code her sehr viel kürzer.

> Die Tabellen von Agner habe ich mir letztes Jahr besorgt.

Die werden stetig aktualisiert, aber der hat wohl nicht immer die
Patte, entsprechend die neuesten CPUs zu kaufen.

Bonita Montero

unread,
Jun 25, 2022, 2:14:36 PM6/25/22
to
Am 25.06.2022 um 19:20 schrieb Helmut Schellong:

> Du hast offenbar nie Optimierungs-Handbücher von Intel gelesen.

Es gibt Optimierungs-Bücher von Intel und AMD, aber da steht nix
bzgl. Latenz und Durchsatz einzelner Instruktionen. Ich mein wie
soll das auch gehen da sich das oft schon zwischen unterschiedlichen
Steppings der selben CPU gravierend ändern kann. Guck dir die einzel-
nen Core i Generationen, die sind stetig fortentwickelt worden und
haben über die Jahre gravierende Effizienz-Steigerungen gemacht.
Willst Du da für 10 oder mehr CPU-Generationen jeweils mehr als
tausend Instruktionen bzgl. Latenz und Laufzeig dokumentieren.
Was glaubste weswegen es agner.org gibt wenn man das bei Intel
doch angeblcih sowieso lesen kann ?

> Und woher stammen genau übereinstimmende Angaben wie '16-126' in der
> Hochschulquelle als auch in  http://www.schellong.de/pent.htm ?

Echt, ich mein wenn Du wirklich Belege hättest, dann würdest Du hier
mit Leichtigkeit ein PDF verlinken und fertig. Da kommst DU mit total
an den Haaren herbeigezogenen indirekten Belegen ....

> Ich habe schon vor langer, langer Zeit Definitionen zu Latency und
> Throughput gelesen.

Vermutlich schon beim 486, wo es keine überappende Ausführung gab;
hrhr. ;-)

> FDIV und FSQRT haben inzwischen nur noch ~16 Takte Latency.
> FDIV 5 und FMUL 2 Takte Throughput.
> Viele FXXX haben nur noch 1..2 Takte Throughput, teilweise 0..½.

Haste bestimmt alles aus den Intel-Manuals, wo Du nur zufällig
gerade keine Zeit hast, die zu suchen, ne ?

> Richtig, das sind keine prinzipiellen Unterschiede in den
> Gleitkomma-Formaten.

Doch, aber ganz gravierend.

> Ich habe 1994 32 Takte Latency für FPREM im Pentium-60 gemessen.
> Inzwischen sind 26..30 angegeben/gemessen. Throughput==17.

Äh, schau dir erstmal die Zahlen von agner.org an,
die sind für aktuelle CPUs durchgängig sehr viel höher,
17 wäre das eher die untere Grenze.


Bonita Montero

unread,
Jun 25, 2022, 2:25:32 PM6/25/22
to
Am 25.06.2022 um 20:08 schrieb Bonita Montero:

> Grundsätzlich find ich aber eine Lösung mit FIST einigermaßen effizient.
> Ich mein man hat 53 Bit Mantisse und wenn die Werte so groß sind, dass
> die nicht mehr in das 64 Bit Integer passen, dann liegt das "virtuelle"
> niederwertigste Bit das über gerade und ungerade entscheidet eben rechts
> von der Mantisse und ist immer Null. D.h. man könnte erstmal schauen,
> ob die Konvertierung gen Integer nicht den magischen Wert 1 << 63 gibt
> und somit gegen einen Überlauf testen - dann ist der Wert so groß, dass
> er sowieso gerade ist, zumindest wenn ich kein Inf oder NaN habe, und
> wenn eben nicht, dann teste ich auf das niederwertigste Bit in einem
> Integer-Register; das kriegst auch Du schnell hin.
> Ich nehm mal stark an, dass das gar nicht so viel langsamer ist als
> meine Lösung, aber eben vom Code her sehr viel kürzer.

Ich hab das gerade mal ausprobiert und meinen ursprünglichen Benchmark
noch um einen weiteren erweitert. Und zwar sieht die Odd-Funktion nach
obigem Schema dann so aus:


bool dIntOdd( double d )
{
constexpr int64_t MAGIC_OVERFLOW_VALUE = 0x8000000000000000u;
int64_t i = (int64_t)d;
if( i == MAGIC_OVERFLOW_VALUE ) [[unlikely]]
{
if( isnan( d ) || isinf( d ) )
feraiseexcept( FE_INVALID );
return false;
}
return i & 1;
}

Das sind die Resultate im Vergleich.

playing with bits: 1.35946
pure math: 20.3645
integer conversion: 1.14356

Hätt ich nicht gedacht, dass diese Lösung noch 19% schneller ist.

Bonita Montero

unread,
Jun 25, 2022, 2:29:58 PM6/25/22
to
Am 25.06.2022 um 19:43 schrieb Helmut Schellong:

> Das sage ich nun zum Dritten Mal:
> Dein Code folgt überhaupt gar nicht diesem oder einem ähnlichen
> Meß-Konzept!
> Du mißt auf sehr ungeeignete Weise! - Ausgerechnet bei Instruktionen!

Nein, tue ich eben nicht. Ganz einfach weil ich erstens Abhängigkeits
-Ketten aufbaue um wirklich die Latenz zu messen; ein Konzept, dass
dir wohl ganz sicher fremd ist. Und zweitens messe ich eine Operation
die zum weitaus größten Teil von einer derart Latenz-lastigen Operation
bestimmt ist, da das Drumherum mehr als vernachlässigbar ist.

> Als Entwicklungsingenieur wärst Du untauglich.

Erstens bin ich kein er, zweitens programmiere ich seitdem ich 10 bin,
also seit 40 Jahren und drittens habe ich ein einschlägiges Studium,
während Du irgendein Elektro-Jofel bist.

> Es geht nicht nur um Performance, sondern beispielsweise auch
> um Homogenität und Vollständigkeit, und sehr geringen Code-Umfang.
> Die Lib mit 59 Funktionen hat nur 2700 Byte.

Wir reden nicht von einem Arduino Uno, sondern einem PC mit massig
Cache und wo 16GB RAM nichtmal 50€ kosten.

Helmut Schellong

unread,
Jun 25, 2022, 4:49:48 PM6/25/22
to
On 06/25/2022 20:08, Bonita Montero wrote:
> Am 25.06.2022 um 19:31 schrieb Helmut Schellong:
>
>>> Die Laufzeit obiger Schleife wird dann so gut wie zu 100% rein durch
>>> das FPREM bestimmt bzw. alle anderen Instruktionen werden durch die
>>> Latenz des FPREMs komplett verdeckt und OoO-parallel ausgeführt.
>>> Bei obiger Schleife kommt dann auf meine CPU bei einem belasteten
>>> Thread ziemlich genau 3,5ns raus, also fast exakt 15 Takte für den
>>> Throughput. Das ist sehr nah dran an dem auf agner.org genannten
>>> minimalen Timing, das aber auch in die Größenordnungen eines
>>> Throughputs von 50 Taktgen gehen kann. D.h. weil die 2.0 wohl so
>>> eine kleine Spanne ihrer signifinanten Bit(s) hat liegt der hier
>>> wohl am unteren Ende.
>
>> Ja, deshalb habe ich meine Lösung mit FIST verworfen und FPREM genommen.
>
> Äh, was hat das genau mit meiner Diskussion um Latenz und Laufzeit
> von FPREM zu tun ?

|D.h. weil die 2.0 wohl so eine kleine Spanne ihrer signifinanten Bit(s)
|hat liegt der hier wohl am unteren Ende.

Du schreibst den Grund selbst und merkst es nicht.

> Grundsätzlich find ich aber eine Lösung mit FIST einigermaßen effizient.
> Ich mein man hat 53 Bit Mantisse und wenn die Werte so groß sind, dass
> die nicht mehr in das 64 Bit Integer passen, dann liegt das "virtuelle"
> niederwertigste Bit das über gerade und ungerade entscheidet eben rechts
> von der Mantisse und ist immer Null. D.h. man könnte erstmal schauen,
> ob die Konvertierung gen Integer nicht den magischen Wert 1 << 63 gibt
> und somit gegen einen Überlauf testen - dann ist der Wert so groß, dass
> er sowieso gerade ist, zumindest wenn ich kein Inf oder NaN habe, und
> wenn eben nicht, dann teste ich auf das niederwertigste Bit in einem
> Integer-Register; das kriegst auch Du schnell hin.

Ich verstehe Dich nicht.
Ich schrieb doch, daß ich eine FIST-Lösung konkret habe!
Und daß ich die verworfen habe, weil ich Sorgen wegen der möglichen Wertgröße habe.
Jetzt kommst Du mit den selben Themen...
(Ich habe 64 Bit Mantisse plus Sign.)

int64_t ste; //<<<<<

"fisttpl %[ste] \n\t" //<<<<<
"fcomip %%st(1), %%st(0) \n\t"
"sete %%dh \n\t"
"jne POWrnz \n\t"
"fwait \n\t"
"testb $1, %[ste] \n\t" //<<<<<
"setnz %%cl \n\t"


> Ich nehm mal stark an, dass das gar nicht so viel langsamer ist als
> meine Lösung, aber eben vom Code her sehr viel kürzer.

Zwei Zeilen ASM-Code.
Und FIST braucht heutzutage nur 5 Takte Latency.

Jedoch bei zu großem Wert gibt es eine Exception, wenn freigegeben,
und FIST wird nicht ausgeführt.

Helmut Schellong

unread,
Jun 25, 2022, 5:36:34 PM6/25/22
to
On 06/25/2022 20:15, Bonita Montero wrote:
> Am 25.06.2022 um 19:20 schrieb Helmut Schellong:
>
>> Du hast offenbar nie Optimierungs-Handbücher von Intel gelesen.
>
> Es gibt Optimierungs-Bücher von Intel und AMD, aber da steht nix
> bzgl. Latenz und Durchsatz einzelner Instruktionen. Ich mein wie
> soll das auch gehen da sich das oft schon zwischen unterschiedlichen
> Steppings der selben CPU gravierend ändern kann. Guck dir die einzel-
> nen Core i Generationen, die sind stetig fortentwickelt worden und
> haben über die Jahre gravierende Effizienz-Steigerungen gemacht.
> Willst Du da für 10 oder mehr CPU-Generationen jeweils mehr als
> tausend Instruktionen bzgl. Latenz und Laufzeig dokumentieren.
> Was glaubste weswegen es agner.org gibt wenn man das bei Intel
> doch angeblcih sowieso lesen kann ?
>
>> Und woher stammen genau übereinstimmende Angaben wie '16-126' in der
>> Hochschulquelle als auch in  http://www.schellong.de/pent.htm ?
>
> Echt, ich mein wenn Du wirklich Belege hättest, dann würdest Du hier
> mit Leichtigkeit ein PDF verlinken und fertig. Da kommst DU mit total
> an den Haaren herbeigezogenen indirekten Belegen ....

Du hast offenbar eine schlimme Krankheit - Alzheimer?
Du unterschlägst Beweise!
Und Du bist unverschämt und nennst Beweise, genau wie agner.org,
|"total an den Haaren herbeigezogenen indirekten Belegen ...."

|Und woher stammen genau übereinstimmende Angaben wie '16-126' in der
|Hochschulquelle als auch in http://www.schellong.de/pent.htm ?
|http://www.schellong.de/img/div/ia32.jpg

Das Bild stammt aus einem Optimierungs-Handbuch von Intel.
Und es zeigt eine Instruktions-Tabelle mit Latency und Throughput.
http://www.schellong.de/pdf/ia32optim.pdf (pdf durch DRM geschützt)

>> Ich habe schon vor langer, langer Zeit Definitionen zu Latency und Throughput gelesen.
>
> Vermutlich schon beim 486, wo es keine überappende Ausführung gab;
> hrhr. ;-)

Nein, aber vor langer, langer Zeit, Du Spinner.
Du hattest behauptet, ich hätte keine Ahnung von Latency und Throughput.

>> FDIV und FSQRT haben inzwischen nur noch ~16 Takte Latency.
>> FDIV 5 und FMUL 2 Takte Throughput.
>> Viele FXXX haben nur noch 1..2 Takte Throughput, teilweise 0..½.
>
> Haste bestimmt alles aus den Intel-Manuals, wo Du nur zufällig
> gerade keine Zeit hast, die zu suchen, ne ?

Aus Intel-Manuals und von agner.
Jahrzehnte alte Intel-Manuals sind nicht mehr download-bar, Du Spinner.

>> Richtig, das sind keine prinzipiellen Unterschiede in den Gleitkomma-Formaten.
>
> Doch, aber ganz gravierend.

Nein, solche Details vertreten nicht die grundlegende Struktur
und grundlegenden Prinzipien von Gleitkomma-Formaten.

>> Ich habe 1994 32 Takte Latency für FPREM im Pentium-60 gemessen.
>> Inzwischen sind 26..30 angegeben/gemessen. Throughput==17.
>
> Äh, schau dir erstmal die Zahlen von agner.org an,
> die sind für aktuelle CPUs durchgängig sehr viel höher,
> 17 wäre das eher die untere Grenze.
>
Die Zahlen sind von agner, Du Spinner.
Allerdings wahrheitsgemäß über neuere Intel-CPUs.

Helmut Schellong

unread,
Jun 25, 2022, 5:44:55 PM6/25/22
to
On 06/25/2022 20:30, Bonita Montero wrote:
> Am 25.06.2022 um 19:43 schrieb Helmut Schellong:
>
>> Das sage ich nun zum Dritten Mal:
>> Dein Code folgt überhaupt gar nicht diesem oder einem ähnlichen Meß-Konzept!
>> Du mißt auf sehr ungeeignete Weise! - Ausgerechnet bei Instruktionen!
>
> Nein, tue ich eben nicht. Ganz einfach weil ich erstens Abhängigkeits
> -Ketten aufbaue um wirklich die Latenz zu messen; ein Konzept, dass
> dir wohl ganz sicher fremd ist.

Platte Behauptung.
Meine Meßmethode ist beträchtlich genauer und konzeptionell besser.
Und sie berücksichtigt auch Throughput-Vermeidung.
Ich habe damit schon 1994 gemessen, wie ich bereits schrieb.

Bonita Montero

unread,
Jun 26, 2022, 12:44:57 AM6/26/22
to
Am 25.06.2022 um 22:50 schrieb Helmut Schellong:

> Zwei Zeilen ASM-Code.

Ich hab dir die richtge Lösung mit FIST gezeigt.

Bonita Montero

unread,
Jun 26, 2022, 12:51:43 AM6/26/22
to
Am 25.06.2022 um 23:37 schrieb Helmut Schellong:

> Das Bild stammt aus einem Optimierungs-Handbuch von Intel.
> Und es zeigt eine Instruktions-Tabelle mit Latency und Throughput.
> http://www.schellong.de/pdf/ia32optim.pdf   (pdf durch DRM geschützt)

Naja, das ist eher ein kleiner Beispiel-hafter Ausschnitt der
Instruktionen; außerdem findest Du da nix direkt zum Pentium.
Irgendwelche längeren Tabellen wie bei agner.org findest Du
sonst weder bei AMD, noch bei Intel.

> Nein, aber vor langer, langer Zeit, Du Spinner.
> Du hattest behauptet, ich hätte keine Ahnung von Latency und Throughput.

Ne, Du weißt nur nicht wie man entsprechende Abhängigkeits-Ketten
bildet, dass man wirklich die Latenz misst, und nicht den Durchsatz.

>>> FDIV und FSQRT haben inzwischen nur noch ~16 Takte Latency.

> Aus Intel-Manuals und von agner.
> Jahrzehnte alte Intel-Manuals sind nicht mehr download-bar, Du Spinner.

Du kannst dir mal die aktuellen Intel-Manuals runterladen;
da wirst Du solche Tabellen nicht finden.

> Nein, solche Details vertreten nicht die grundlegende Struktur
> und grundlegenden Prinzipien  von Gleitkomma-Formaten.

Echt, Du schwurbelst dir da einen rum.

> Die Zahlen sind von agner, Du Spinner.
> Allerdings wahrheitsgemäß über neuere Intel-CPUs.

Ja, aber Du gibst einen einzelnen Wert an wo es eine Spanne gibt.
Und dieser einzelne Wert ist dann eher der minimale Througput,
die obere Grenze davon ein Vielfaches.

Bonita Montero

unread,
Jun 26, 2022, 1:12:40 AM6/26/22
to
Am 25.06.2022 um 23:45 schrieb Helmut Schellong:
> On 06/25/2022 20:30, Bonita Montero wrote:
>> Am 25.06.2022 um 19:43 schrieb Helmut Schellong:
>>
>>> Das sage ich nun zum Dritten Mal:
>>> Dein Code folgt überhaupt gar nicht diesem oder einem ähnlichen
>>> Meß-Konzept!
>>> Du mißt auf sehr ungeeignete Weise! - Ausgerechnet bei Instruktionen!
>>
>> Nein, tue ich eben nicht. Ganz einfach weil ich erstens Abhängigkeits
>> -Ketten aufbaue um wirklich die Latenz zu messen; ein Konzept, dass
>> dir wohl ganz sicher fremd ist.
>
> Platte Behauptung.

Wie, Behauptung ?
Alles was ich hier gepostet habe tut das.

> Meine Meßmethode ist beträchtlich genauer und konzeptionell besser.

Das trau ich dir nicht zu.

> Und sie berücksichtigt auch Throughput-Vermeidung.

Througpuput-Vermeidung - au weia, was für'n Wort.

Bonita Montero

unread,
Jun 26, 2022, 1:14:32 AM6/26/22
to
Ne, hab ich eigentlich nicht, denn ich habe ja die C-Lösung genutzt
mit einem Cast, und die mappt ja auf SSE, AVX, oder was der Compiler
gerade für angemessen hält.
Die korrekte x87-Lösung ist sicher sehr viel länger als mit fünf
Instruktionen:

fld qword ptr [rcx]
fistp qword ptr [rsp - 8]
mov rax, [rsp - 8]
mov rdx, 08000000000000000h
cmp rax, rdx
je overflow
and al, 1
ret
overflow:
mov rax, [rcx]
shr rax, 52
and ax, 07FFh
cmp ax, 07FFh
je nanInf
xor al, al
ret
nanInf:
; generate invalid exception
fldz
fldz
fdivp
fstp st
ret

Sowas kriegst Du eher nicht hin.

Helmut Schellong

unread,
Jun 26, 2022, 4:39:58 AM6/26/22
to
Was soll das heißen?
Daß meine Lösung falsch ist?
Meine Lösung hat schon vor Wochen funktioniert.

Übrigens kann eine FIST-Lösung gar nicht falsch sein.
fist[p] mem
Das muß ja zwangsläufig so formuliert werden.
Du spinnst mal wieder rum...

Helmut Schellong

unread,
Jun 26, 2022, 5:32:36 AM6/26/22
to
On 06/26/2022 06:52, Bonita Montero wrote:
> Am 25.06.2022 um 23:37 schrieb Helmut Schellong:
>
>> Das Bild stammt aus einem Optimierungs-Handbuch von Intel.
>> Und es zeigt eine Instruktions-Tabelle mit Latency und Throughput.
>> http://www.schellong.de/pdf/ia32optim.pdf   (pdf durch DRM geschützt)
>
> Naja, das ist eher ein kleiner Beispiel-hafter Ausschnitt der
> Instruktionen; außerdem findest Du da nix direkt zum Pentium.

Ich habe auch die ganze pdf verlinkt, nicht nur ein jpg-Bild daraus.
Ist ja vorstehend die 'ia32optim.pdf'.
Diese verschweigst Du, obwohl sie vorstehend lesbar ist.

Beweise zum Pentium habe ich mehrfach gepostet.
Du verschweigst sie halt und forderst sie dennoch an, obwohl bereits gepostet.

Agner hat auch Pentium gemessen - was Du aber verschweigst:
Pentium, Pentium MMX, Pentium II, Pentium III, Pentium M.
Agners Messungen stimmen mit meinen von 1994 überein ( http://www.schellong.de/pent.htm ).

Du bist ein Betrüger und Spinner, der ständig sichtbare Beweise nullifiziert,
diese aber ständig neu fordert, obwohl sie längst da sind.

> Irgendwelche längeren Tabellen wie bei agner.org findest Du
> sonst weder bei AMD, noch bei Intel.

|Intel® Xeon® Scalable Processor Instruction Throughput and Latency
|Date: August 2017 Intel® Xeon® Scalable Processor Instruction Throughput and Latency (DCU) hit.

Was haben wir denn da vorstehend?!
Eine ganze pdf mit 132 Seiten (!) Instruktions-Tabellen.
|XED_IFORM_ADCX_GPR32d_GPR32d adcx eax, ecx 1 0.5

Intel hat darin schon das neue Format, wie in den .csv-Dateien.

>> Nein, aber vor langer, langer Zeit, Du Spinner.
>> Du hattest behauptet, ich hätte keine Ahnung von Latency und Throughput.
>
> Ne, Du weißt nur nicht wie man entsprechende Abhängigkeits-Ketten
> bildet, dass man wirklich die Latenz misst, und nicht den Durchsatz.

Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.
Da kann ich aus mehreren Mitteln aussuchen.
Du willst jedoch von professionellem Messen nichts wissen, wie ich feststellte.

>>>> FDIV und FSQRT haben inzwischen nur noch ~16 Takte Latency.
>
>> Aus Intel-Manuals und von agner.
>> Jahrzehnte alte Intel-Manuals sind nicht mehr download-bar, Du Spinner.
>
> Du kannst dir mal die aktuellen Intel-Manuals runterladen;
> da wirst Du solche Tabellen nicht finden.

Ja, das stimmt, und das habe ich hier bereits geschrieben.
Ich habe selbst _aktuelle_ pdf, mit 2200 und >5000 Seiten.
Da sind solche Tabellen nicht enthalten.
Du hast aber behauptet, Intel habe niemals solche Tabellen in den Manuals gehabt.

>> Nein, solche Details vertreten nicht die grundlegende Struktur
>> und grundlegenden Prinzipien  von Gleitkomma-Formaten.
>
> Echt, Du schwurbelst dir da einen rum.
>
>> Die Zahlen sind von agner, Du Spinner.
>> Allerdings wahrheitsgemäß über neuere Intel-CPUs.
>
> Ja, aber Du gibst einen einzelnen Wert an wo es eine Spanne gibt.
> Und dieser einzelne Wert ist dann eher der minimale Througput,
> die obere Grenze davon ein Vielfaches.

Ich gebe einzelne Latency-Meßwerte an, in meiner http://www.schellong.de/pent.htm
Meistens habe ich 5-10 Messungen vorgenommen, und denjenigen Wert angegeben, der
mit Abstand am häufigsten vorkam. Die Streuung war gering, etwa 5%.

Eine wirkliche Spanne gibt es nur, wenn z.B. mit stark unterschiedlichen Werten gemessen wird.
Ich habe stets realistische, ehrliche Werte den Instruktionen aufgegeben.

Helmut Schellong

unread,
Jun 26, 2022, 5:57:00 AM6/26/22
to
On 06/26/2022 07:13, Bonita Montero wrote:
> Am 25.06.2022 um 23:45 schrieb Helmut Schellong:
>> On 06/25/2022 20:30, Bonita Montero wrote:
>>> Am 25.06.2022 um 19:43 schrieb Helmut Schellong:
>>>
>>>> Das sage ich nun zum Dritten Mal:
>>>> Dein Code folgt überhaupt gar nicht diesem oder einem ähnlichen Meß-Konzept!
>>>> Du mißt auf sehr ungeeignete Weise! - Ausgerechnet bei Instruktionen!
>>>
>>> Nein, tue ich eben nicht. Ganz einfach weil ich erstens Abhängigkeits
>>> -Ketten aufbaue um wirklich die Latenz zu messen; ein Konzept, dass
>>> dir wohl ganz sicher fremd ist.
>>
>> Platte Behauptung.
>
> Wie, Behauptung ?
> Alles was ich hier gepostet habe tut das.

Du hast doch vorstehend lesbar behauptet:
|"ein Konzept, dass dir wohl ganz sicher fremd ist."

Es ist jedoch so, daß ich die Definitionen von Latency und Throughput
seit den späten 1990ern oder den frühen 2000ern kenne.

>> Meine Meßmethode ist beträchtlich genauer und konzeptionell besser.
>
> Das trau ich dir nicht zu.

Aha, einem Entwicklungsingenieur traust Du keine gute Meßmethode zu?!

Ich habe meine Meßmethode hier dargelegt, beschrieben und sogar mathematisch bewiesen!
Das steht hier in meinem Posting 06/25/2022 05:12.

>> Und sie berücksichtigt auch Throughput-Vermeidung.
>
> Througpuput-Vermeidung - au weia, was für'n Wort.

Ein Throughput-Resultat sollte vermieden werden, da solche Ergebnisse
in der Praxis unrealistisch und damit /unehrlich/ wirken.

Helmut Schellong

unread,
Jun 26, 2022, 6:25:25 AM6/26/22
to
Solch einen Unfug will ich gar nicht 'hinkriegen'!
Was ich hinkriege, ist in meiner Library zu sehen:
http://www.schellong.de/txt/asm87c.c
Die Verwendung von rxx-Registern ist bereits die Portabilität einschränkend.
So etwas habe ich in meiner Lib vermieden.

Bereits die Instruktion fistp löst eine Exception aus und wird
abgebrochen, wenn der umzuwandelnde Wert zu groß für den Integer ist.

|FIST/FISTP—Store Integer
|If the converted value is too large for the destination format, or if the
|source operand is an ∞, SNaN, QNAN, or is in an unsupported format, an
|invalid-arithmetic-operand condition is signaled.
|If the invalid-operation exception is not masked, an invalid-arithmetic-operand
|exception (#IA) is generated and no value is stored in the destination operand.
|If the invalid-operation exception is masked, the integer indefinite value is stored in memory.

Bonita Montero

unread,
Jun 26, 2022, 8:06:00 AM6/26/22
to
Am 26.06.2022 um 12:25 schrieb Helmut Schellong:

> Solch einen Unfug will ich gar nicht 'hinkriegen'!

Das ist kein Unfug, sondern eine absolut minimale und korrekte
Implementation mit FIST.

> Die Verwendung von rxx-Registern ist bereits die Portabilität
> einschränkend.

Die Verwendung von 32 Bit Registern ebenso.

> So etwas habe ich in meiner Lib vermieden.

Das kann man nicht _vermeiden_, sondern sich nur für die eine
oder andere Plattform entscheiden.

> Bereits die Instruktion fistp löst eine Exception aus und wird
> abgebrochen, wenn der umzuwandelnde Wert zu groß für den Integer ist.

Das ist egal, denn FP-Exceptions sind in C nur Flags und das
wird dann ggf. in meinem zweiten "if"-Zweig nochmal generiert.
D.h. man meinem Code ist nichts was nicht funktioniert.
Das was ich da doppelt mache ist im Endeffekt schneller als
würde ich das FPU Control word noch händisch auswerten.

Bonita Montero

unread,
Jun 26, 2022, 8:07:01 AM6/26/22
to
Am 26.06.2022 um 10:40 schrieb Helmut Schellong:
> On 06/26/2022 06:45, Bonita Montero wrote:
>> Am 25.06.2022 um 22:50 schrieb Helmut Schellong:
>>
>>> Zwei Zeilen ASM-Code.
>>
>> Ich hab dir die richtge Lösung mit FIST gezeigt.
>
> Was soll das heißen?
> Daß meine Lösung falsch ist?
> Meine Lösung hat schon vor Wochen funktioniert.

Deine "Lösung" berücksichtigt nicht, dass wenn der FP-Wert ganzzahlig
ist und das niederwertigste Bit sich virtuell rechts von der Mantisse
befindet, dass man das dann auch als gerade werten muss.

Bonita Montero

unread,
Jun 26, 2022, 8:13:11 AM6/26/22
to
Am 26.06.2022 um 11:33 schrieb Helmut Schellong:

>> Ne, Du weißt nur nicht wie man entsprechende Abhängigkeits-Ketten
>> bildet, dass man wirklich die Latenz misst, und nicht den Durchsatz.

> Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.

Dann zeig mir mal eine Schleife die die wiederholt FPREM aufruft und
dabei nicht dessen Durchsatz, sondern die Latenz "misst", bzw. die
Messung will ich gar nicht haben, nur den Code, dass eine gedachte
Messung drumherum eben korrekt wäre.

>> Ja, aber Du gibst einen einzelnen Wert an wo es eine Spanne gibt.
>> Und dieser einzelne Wert ist dann eher der minimale Througput,
>> die obere Grenze davon ein Vielfaches.
>
> Ich gebe einzelne Latency-Meßwerte an, in meiner
> http://www.schellong.de/pent.htm

Äh, die Diskussion ging zuletzt um FPREM, und da hast Du dich weder
explizit auf Latenz, noch Durchsatz bezogen, sondern einfach nur
gesagt, dass das angeblich 17 Takte dauert, und dass das ja so auch
bei Agner ständ.
Ich sagte dazu nur, dass

> Ich habe stets realistische, ehrliche Werte den Instruktionen aufgegeben.

Du bist ein kompletter Idiot.

Bonita Montero

unread,
Jun 26, 2022, 8:15:52 AM6/26/22
to
Am 26.06.2022 um 11:57 schrieb Helmut Schellong:

> Es ist jedoch so, daß ich die Definitionen von Latency und
> Throughput seit den späten 1990ern oder den frühen 2000ern kenne.

Das mag man kennen, aber deswegen weiß man nicht automatisch, wie
man eine Mess-Schleife schreibt die die Latenz auch korrekt misst.
Ich habe das korrekt gemessen.
Nochmal: Zeig mir mal eine FPREM Mess-Schleife mit der ess mit
zusätzlicher Mess-Instrumentierung möglich wäre, die Latenz von
FPREM zu messen. Wetten, dass Du das nicht auf die Kette kriegst ?

> Ein Throughput-Resultat sollte vermieden werden, da solche
> Ergebnisse in der Praxis unrealistisch und damit /unehrlich/
> wirken.

Äh, wo hab ich weas Gegenteiliges gesagt ?

Bonita Montero

unread,
Jun 26, 2022, 9:55:00 AM6/26/22
to
Am 26.06.2022 um 14:06 schrieb Bonita Montero:

> Das ist egal, denn FP-Exceptions sind in C nur Flags und das
> wird dann ggf. in meinem zweiten "if"-Zweig nochmal generiert.
> D.h. man meinem Code ist nichts was nicht funktioniert.
> Das was ich da doppelt mache ist im Endeffekt schneller als
> würde ich das FPU Control word noch händisch auswerten.

Mir ist gerade durch den Kopf gegangen, warum das mit der Abfrage des
Exception-Flags recht problematisch wäre: das Flag ist nämlich sticky,
d.h. ich müsste mir dessen alten Zustand vorher merken, es zurücksetzen,
dann die Konvertierung durchführen, dann das Flag abfragen ... und am
Ende das vorherige Flag mit dem selbst gesetzten, falls der Operand
eben Inf oder NaN war, oder nehmen. Ein wenig aufwendig, nicht ?

Also, wenn Du es meinst besser zu können, Helmut, dann poste
_hier_ doch mal deine Lösung mit FIST, ich zerleg die dann.

Helmut Schellong

unread,
Jun 26, 2022, 2:32:23 PM6/26/22
to
On 06/26/2022 14:06, Bonita Montero wrote:
> Am 26.06.2022 um 12:25 schrieb Helmut Schellong:
>
>> Solch einen Unfug will ich gar nicht 'hinkriegen'!
>
> Das ist kein Unfug, sondern eine absolut minimale und korrekte
> Implementation mit FIST.

Eine absolut minimale und korrekte Implementation von FIST ist:
fist mem
Deine 20 ASM-Zeilen sind Unfug.
Du mußt auch nicht 0/0 durchführen, sondern x/0 reicht.

>> Die Verwendung von rxx-Registern ist bereits die Portabilität einschränkend.
>
> Die Verwendung von 32 Bit Registern ebenso.

Nein.
Portabilität für den 32-bit-Modus muß zwar vorliegen.
Aber portabel für 8086, 80186, 80286 braucht es wirklich nicht zu sein.

>> So etwas habe ich in meiner Lib vermieden.
>
> Das kann man nicht _vermeiden_, sondern sich nur für die eine
> oder andere Plattform entscheiden.

Ich habe es erfolgreich vermieden.
Und ich habe das bisher mehrfach berichtet.
Du wirst keine Verwendung von rxx-Registern in meinem Inline-Assembler finden.
Es gibt auch keine Verwendung der Instruktion sahf.
Ich kann es im 32-Bit-Modus als auch im 64-Bit-Modus kompilieren.
Und die Test.exe funktioniert in beiden Fällen.
(-m32: 375180 Jun 24 20:20 a.out; -m64: 482328 Jun 24 21:08 a.out)

> [...]
Unfug bleibt Unfug.

Helmut Schellong

unread,
Jun 26, 2022, 2:47:52 PM6/26/22
to
Nein, muß man nicht.
Ich bewerte den gespeicherten Integer.
Schau die ST(0):DEST-Tabelle in der Referenz an.

Ich bewerte doch nicht die Bits des Gleitkomma-Wertes bei einer FIST!

Helmut Schellong

unread,
Jun 26, 2022, 3:00:25 PM6/26/22
to
On 06/26/2022 14:13, Bonita Montero wrote:
> Am 26.06.2022 um 11:33 schrieb Helmut Schellong:
>
>>> Ne, Du weißt nur nicht wie man entsprechende Abhängigkeits-Ketten
>>> bildet, dass man wirklich die Latenz misst, und nicht den Durchsatz.
>
>> Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.
>
> Dann zeig mir mal eine Schleife die die wiederholt FPREM aufruft und
> dabei nicht dessen Durchsatz, sondern die Latenz "misst", bzw. die
> Messung will ich gar nicht haben, nur den Code, dass eine gedachte
> Messung drumherum eben korrekt wäre.

Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.
Ich habe keine Lust, Dir mit Deinem ungeeigneten Meßkonzept das vorzuführen.
Mit meinem Meßkonzept kann ich verschiedene Methoden wählen, korrekt
die Latenz zu messen. (Sagte ich bereits.)
Mein Meßkonzept habe ich bereits mehrfach dargelegt.

>>> Ja, aber Du gibst einen einzelnen Wert an wo es eine Spanne gibt.
>>> Und dieser einzelne Wert ist dann eher der minimale Througput,
>>> die obere Grenze davon ein Vielfaches.
>>
>> Ich gebe einzelne Latency-Meßwerte an, in meiner http://www.schellong.de/pent.htm
>
> Äh, die Diskussion ging zuletzt um FPREM, und da hast Du dich weder
> explizit auf Latenz, noch Durchsatz bezogen, sondern einfach nur
> gesagt, dass das angeblich 17 Takte dauert, und dass das ja so auch
> bei Agner ständ.

Nein, ich schrieb mehrfach, daß ich 1994 32 Takte Latenz gemessen habe
und daß inzwischen 26..30 Takte angegeben wird.
Durchsatz habe ich nie gemessen.

>
>> Ich habe stets realistische, ehrliche Werte den Instruktionen aufgegeben.
>
> Du bist ein kompletter Idiot.

Und Du reißt ein Teilthema abermals aus seinem Kontext.

Helmut Schellong

unread,
Jun 26, 2022, 3:07:11 PM6/26/22
to
On 06/26/2022 14:16, Bonita Montero wrote:
> Am 26.06.2022 um 11:57 schrieb Helmut Schellong:
>
>> Es ist jedoch so, daß ich die Definitionen von Latency und
>> Throughput seit den späten 1990ern oder den frühen 2000ern kenne.
>
> Das mag man kennen, aber deswegen weiß man nicht automatisch, wie
> man eine Mess-Schleife schreibt die die Latenz auch korrekt misst.
> Ich habe das korrekt gemessen.
> Nochmal: Zeig mir mal eine FPREM Mess-Schleife mit der ess mit
> zusätzlicher Mess-Instrumentierung möglich wäre, die Latenz von
> FPREM zu messen. Wetten, dass Du das nicht auf die Kette kriegst ?

Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.
Ich habe keine Lust, Dir mit Deinem ungeeigneten Meßkonzept das vorzuführen.
Mit meinem Meßkonzept kann ich verschiedene Methoden wählen, korrekt
die Latenz zu messen. (Sagte ich bereits.)
Mein Meßkonzept habe ich bereits mehrfach dargelegt.

>> Ein Throughput-Resultat sollte vermieden werden, da solche
>> Ergebnisse in der Praxis unrealistisch und damit /unehrlich/
>> wirken.
>
> Äh, wo hab ich weas Gegenteiliges gesagt ?

Nein, aber wenn ich Throughput-Messungen vermeide, bedeutet das, daß ich Latenz messe.

Meine Meßwerte von 1994 in http://www.schellong.de/pent.htm
stimmen mit den Latenz-Zeiten von Agner überein.
Folglich sind es Latenz-Messungen gewesen.

Helmut Schellong

unread,
Jun 26, 2022, 3:11:22 PM6/26/22
to
Ich habe meine FIST-Lösung bereits in 06/25/2022 22:50 gepostet.
Ich wüßte nicht, warum ich sie nochmals posten sollte.

Bonita Montero

unread,
Jun 26, 2022, 11:24:14 PM6/26/22
to
Am 26.06.2022 um 21:11 schrieb Helmut Schellong:
> On 06/26/2022 15:55, Bonita Montero wrote:
>> Am 26.06.2022 um 14:06 schrieb Bonita Montero:
>>
>>> Das ist egal, denn FP-Exceptions sind in C nur Flags und das
>>> wird dann ggf. in meinem zweiten "if"-Zweig nochmal generiert.
>>> D.h. man meinem Code ist nichts was nicht funktioniert.
>>> Das was ich da doppelt mache ist im Endeffekt schneller als
>>> würde ich das FPU Control word noch händisch auswerten.
>>
>> Mir ist gerade durch den Kopf gegangen, warum das mit der Abfrage des
>> Exception-Flags recht problematisch wäre: das Flag ist nämlich sticky,
>> d.h. ich müsste mir dessen alten Zustand vorher merken, es zurücksetzen,
>> dann die Konvertierung durchführen, dann das Flag abfragen ... und am
>> Ende das vorherige Flag mit dem selbst gesetzten, falls der Operand
>> eben Inf oder NaN war, oder nehmen. Ein wenig aufwendig, nicht ?
>>
>> Also, wenn Du es meinst besser zu können, Helmut, dann poste
>> _hier_ doch mal deine Lösung mit FIST, ich zerleg die dann.
>
> Ich habe meine FIST-Lösung bereits in  06/25/2022 22:50  gepostet.
> Ich wüßte nicht, warum ich sie nochmals posten sollte.

Natürlich weißt Du, warum Du das nicht tust:
damit ich deinen Mist nicht zerlege.

Bonita Montero

unread,
Jun 26, 2022, 11:26:40 PM6/26/22
to
Am 26.06.2022 um 20:32 schrieb Helmut Schellong:

> Eine absolut minimale und korrekte Implementation von FIST ist:
>     fist  mem
> Deine 20 ASM-Zeilen sind Unfug.
> Du mußt auch nicht 0/0 durchführen, sondern x/0 reicht.

Das ist verkehrt, denn dann würdest Du den Throughput messen,
nicht die Latenz.
Außerdem ist hier ein wenig mehr gefragt, nämlich ein Gerade
/ Ungerade Erkennung,

> Nein.
> Portabilität für den 32-bit-Modus muß zwar vorliegen.

Der Code ist für 32 und 64 Plattformen prinzipiell sehr ähnlich.

> Ich habe es erfolgreich vermieden.

Nein, Du konntest es gar nicht nutzen im 32 Bit Modus,
also nix von "vermeiden".

Bonita Montero

unread,
Jun 26, 2022, 11:27:20 PM6/26/22
to
Am 26.06.2022 um 20:48 schrieb Helmut Schellong:

>> Deine "Lösung" berücksichtigt nicht, dass wenn der FP-Wert ganzzahlig
>> ist und das niederwertigste Bit sich virtuell rechts von der Mantisse
>> befindet, dass man das dann auch als gerade werten muss.

> Nein, muß man nicht.

Für eine korrekte Implementation muss man das definitiv.
Sonst ist die Murks.

Bonita Montero

unread,
Jun 26, 2022, 11:29:18 PM6/26/22
to
Am 26.06.2022 um 21:00 schrieb Helmut Schellong:

> Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.

Ja, deswegen meintest Du ja gerade, dass ein FIST zur Messung
ohne alles reicht; Depp.

> Ich habe keine Lust, Dir mit Deinem ungeeigneten Meßkonzept das
> vorzuführen.

Bitte mach an meinem Source fest, wo mein Konzept ungeeignet ist.

> Nein, ich schrieb mehrfach, daß ich 1994 32 Takte Latenz gemessen habe
> und daß inzwischen 26..30 Takte angegeben wird.

Nein, die Diskussion ging gerade um aktuelle CPUs und Du hast dich
dementsprechend auf Agner bezog.

> Und Du reißt ein Teilthema abermals aus seinem Kontext.

WIe ich gerade gezeigt hast kannst Du einen roten Faden so
gut verfolgen wie einer mit Demenz.

Bonita Montero

unread,
Jun 26, 2022, 11:31:12 PM6/26/22
to
Am 26.06.2022 um 21:07 schrieb Helmut Schellong:

> Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.
> Ich habe keine Lust, Dir mit Deinem ungeeigneten Meßkonzept das
> vorzuführen.

Zeig mir bitte an meinem Source, was da ungeeinget ist !

> Mit meinem Meßkonzept kann ich verschiedene Methoden wählen, korrekt
> die Latenz zu messen. (Sagte ich bereits.)

Da gibt es nicht verschiedene Methoden, sondern eine.

> Meine Meßwerte von 1994 in  http://www.schellong.de/pent.htm
> stimmen mit den Latenz-Zeiten von Agner überein.

Äh, Agner gibt gar keine Daten für so uralte CPUs an !

Bonita Montero

unread,
Jun 27, 2022, 12:55:12 AM6/27/22
to
Hier, die einzig korrekte Implementation in 32 Bit x86 Assembler.

.386
.model flat

PUBLIC ?dIntOddX87@@YI_NABN@Z

_TEXT SEGMENT
?dIntOddX87@@YI_NABN@Z PROC
fld qword ptr [ecx]
fistp qword ptr [esp - 8]
mov eax, [esp - 8]
mov edx, [esp - 4]
cmp edx, 080000000h
je up8
nonOverflow:
and al, 1
ret
up8:
test eax, eax
jnz nonOverflow
mov ax, [ecx + 6]
shr ax, 4
and ax, 07FFh
cmp ax, 07FFh
je nanInf
xor al, al
ret
nanInf:
; generate invalid exception
fldz
fldz
fdivp
fstp st
xor al, al
ret
?dIntOddX87@@YI_NABN@Z ENDP
_TEXT ENDS

END

* Erkennt Überläufe bei der Konvertierung zu Integern.
* Kann Integer-Werte handeln wo das Even / Odd Bit nicht
mehr Teil der physischen Mantisse ist.
* Handelt Inf / Nan korrekt.

Kann deine Implementation alles nicht.

Bonita Montero

unread,
Jun 27, 2022, 3:06:09 AM6/27/22
to
Mir ist da was durch den Kopf gegangen: die Invalid Exception brauch
ich ja eh nicht auszulösen weil FIST das ja selbst tut. Helmut hat
das nicht direkt so gesehen, sondern es an erster Stelle als Fehler
betrachtet, dass ich mich nicht direkt um diese Exception kümmere.
Desweiteren wird bei einem Überlauf durch FIST gen int64_t ja der
magische Wert 1 << 63 generiert. Bei diesem ist das unterste Bit
ja eh Null, d.h. wenn ich einen Wert habe der ganzzahlig ist, aber
wo das Even / Odd Bit virutell rechts von der Mantisse liegt, dann
tritt ja dieser Überlauf-Fall ein und das unterste Bit des magischen
Werts ist eh Null.
D.h. das Ganze lässt sich so weit reduzieren:

64 Bit:

fld qword ptr [rcx]
fistp qword ptr [rsp - 8]
mov al, [rsp - 8]
and al, 1
ret

32 Bit:

fld qword ptr [ecx]
fistp qword ptr [esp - 8]
mov al, [esp - 8]
and al, 1
ret

Ich mein Helmut will jetzt sicher alles so vorher gewusst haben,
hat aber nicht ansatzweise irgendwas gesagt, was obigem Gedankengang
entspricht. Der ist auch gar nicht in der Lage, zwischen intuitiv
-sprachlichem analytischem Denken gut zu pendeln.
Ein Blindes Huhn findet auch ein Korn.

Helmut Schellong

unread,
Jun 27, 2022, 5:45:41 AM6/27/22
to
Du Spinner, jetzt wirst Du wirklich irrsinnig.

Ich habe meine FIST-Lösung bereits vor Tagen gepostet.
Du konntest/kannst sie seitdem zerlegen, wenn Du wolltest/willst.

Helmut Schellong

unread,
Jun 27, 2022, 6:38:12 AM6/27/22
to
On 06/27/2022 05:27, Bonita Montero wrote:
> Am 26.06.2022 um 20:32 schrieb Helmut Schellong:
>
>> Eine absolut minimale und korrekte Implementation von FIST ist:
>>      fist  mem
>> Deine 20 ASM-Zeilen sind Unfug.
>> Du mußt auch nicht 0/0 durchführen, sondern x/0 reicht.
>
> Das ist verkehrt, denn dann würdest Du den Throughput messen,
> nicht die Latenz.
> Außerdem ist hier ein wenig mehr gefragt, nämlich ein Gerade
> / Ungerade Erkennung,

Hää?

>> Nein.
>> Portabilität für den 32-bit-Modus muß zwar vorliegen.
>
> Der Code ist für 32 und 64 Plattformen prinzipiell sehr ähnlich.

Ja - und?

>> Ich habe es erfolgreich vermieden.
>
> Nein, Du konntest es gar nicht nutzen im 32 Bit Modus,
> also nix von "vermeiden".
>

Selbstverständlich habe ich die Verwendung von 64-Bit-Registern rxx vermieden.
Wenn ich es nicht vermieden hätte, würde es im 32-Bit-Modus Fehlermeldungen
und Abbruch geben.
Und Du begreifst immer noch nicht das Erweiterte Inline-Assembling.
Der Compiler wählt automatisch 'eax' im 32-Bit-Modus und 'rax' im 64-Bit-Modus!

Ich darf z.B. nicht 'push eax' für den 64-Bit-Modus schreiben.
Es muß 'push rax' sein.
Wenn ich das jedoch schriebe, würde es im 32-Bit-Modus Fehler und Abbruch geben.
Folglich habe ich 'push reg' komplett _vermieden_, während ich 'push mem' verwende.
Auch 'sahf' habe ich _vermieden_, weil die im 64-Bit-Modus ungültig ist.

Helmut Schellong

unread,
Jun 27, 2022, 6:41:02 AM6/27/22
to
On 06/27/2022 05:27, Bonita Montero wrote:
Dann wären ja alle bestimmungsgemäßen Verwendungen von FIST ungültig!

Ich kann den Referenz-Büchern von Intel solche Notwendigkeiten nicht entnehmen.

Helmut Schellong

unread,
Jun 27, 2022, 6:45:22 AM6/27/22
to
On 06/27/2022 05:29, Bonita Montero wrote:
> Am 26.06.2022 um 21:00 schrieb Helmut Schellong:
>
>> Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.
>
> Ja, deswegen meintest Du ja gerade, dass ein FIST zur Messung
> ohne alles reicht; Depp.

Nein, ich benutzte FIST zur Feststellung von 'Ungerade'.
Mit 'Messung' kann ich in dem Zusammenhang nichts anfangen.

>> Ich habe keine Lust, Dir mit Deinem ungeeigneten Meßkonzept das vorzuführen.
>
> Bitte mach an meinem Source fest, wo mein Konzept ungeeignet ist.

Das habe ich bereits mehrmals getan.
Noch einmal gibt es das nicht.

>> Nein, ich schrieb mehrfach, daß ich 1994 32 Takte Latenz gemessen habe
>> und daß inzwischen 26..30 Takte angegeben wird.
>
> Nein, die Diskussion ging gerade um aktuelle CPUs und Du hast dich
> dementsprechend auf Agner bezog.

Keine Ahnung.
Ich schrieb das, was ich oben angab, geschrieben zu haben.

Helmut Schellong

unread,
Jun 27, 2022, 7:04:51 AM6/27/22
to
On 06/27/2022 05:31, Bonita Montero wrote:
> Am 26.06.2022 um 21:07 schrieb Helmut Schellong:
>
>> Ich weiß schon seit langer, langer Zeit, wie man die Latenz mißt.
>> Ich habe keine Lust, Dir mit Deinem ungeeigneten Meßkonzept das vorzuführen.
>
> Zeig mir bitte an meinem Source, was da ungeeinget ist !

Das habe ich bereits mehrmals getan.
Noch einmal gibt es das nicht.

>> Mit meinem Meßkonzept kann ich verschiedene Methoden wählen, korrekt
>> die Latenz zu messen. (Sagte ich bereits.)
>
> Da gibt es nicht verschiedene Methoden, sondern eine.

Falsch, mit _meinem_ Meßkonzept gibt es mehrere Methoden.

>> Meine Meßwerte von 1994 in  http://www.schellong.de/pent.htm
>> stimmen mit den Latenz-Zeiten von Agner überein.
>
> Äh, Agner gibt gar keine Daten für so uralte CPUs an !
>

Doch, ich habe von diesen Daten sogar schon hier geschrieben:
06/26/2022 11:33
|Agner hat auch Pentium gemessen - was Du aber verschweigst:
|Pentium, Pentium MMX, Pentium II, Pentium III, Pentium M.
|Agners Messungen stimmen mit meinen von 1994 überein ( http://www.schellong.de/pent.htm ).


Bonita Montero

unread,
Jun 27, 2022, 7:30:55 AM6/27/22
to
Am 27.06.2022 um 12:38 schrieb Helmut Schellong:

>> Der Code ist für 32 und 64 Plattformen prinzipiell sehr ähnlich.

> Ja - und?

Du hast meinen Code so aufgefasst, als wäre er verkehrt.

> Selbstverständlich habe ich die Verwendung von 64-Bit-Registern rxx
> vermieden.

Boah, ich beiß gleich in die Tischkante.
Vermeiden kann man nur etwas, was einem als Handlungs-Option offensteht.
Und die 64 Bit Register sind dir nicht im 32 Bit Modus zugänglich; also
kannst Du das auch nicht "vermeiden".

Bonita Montero

unread,
Jun 27, 2022, 7:33:12 AM6/27/22
to
Am 27.06.2022 um 12:45 schrieb Helmut Schellong:

>>> Ich habe keine Lust, Dir mit Deinem ungeeigneten Meßkonzept das
>>> vorzuführen.

>> Bitte mach an meinem Source fest, wo mein Konzept ungeeignet ist.

> Das habe ich bereits mehrmals getan.
> Noch einmal gibt es das nicht.

Ne, da kam keine technische Kritik, sondern dummes Rumgepöbel.

> Keine Ahnung.
> Ich schrieb das, was ich oben angab, geschrieben zu haben.

Ich hab das besser im Überblick, was Du hier geschrieben hast.

It is loading more messages.
0 new messages