Forum: Compiler & IDEs Fixed-Point Support in avr-gcc?


von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Eine Frage die Allgemeinheit:

Wie sinvoll / unsinnig / überflüssig wäre Fixed-Point Unterstützung in 
avr-gcc?

Eine solche auf ISO/IEC TR 18037 "Emdedded-C" basierende Unterstützung 
war für avr-gcc 4.8 geplant und ist in ähnlicher Form bereits in den 
Atmel-Tools basierend auf avr-gcc 4.6 enthalten.

Aspekte sind u.a:

• Effizient im Vergleich zu float oder einer eigenen
  Fixed-Arithmetik

• Klarheit der Quelle mit Ausdrücken wie 1.2k * x + y anstatt
  x-fach verschachtelter Konversionen / Funktionsaufrufen / Makros

• Aufwand / Testabdeckung im Vergleich zur eigenen Arithmetik.

• Einfaches Lesen aus dem Flash (mit C++ zB nicht möglich, auch nicht
  mit pgm_read)

• Skalierbarkeit was den Wertebereich / Position des Dezimalpunkts
  angeht.

• "Emdedded C" (das zB auch __flash implementiert) ist nicht in den
  C-Standard aufgenommen, auch nicht in C11.  Gleichwohl gibt es den
  Quasi-Standard "Emdedded C"

• Destabilisierung der Toolchain durch neue Features

Wiki: Festkommaarithmetik, AVR Arithmetik/Saturierung

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Wie sinvoll / unsinnig / überflüssig wäre Fixed-Point
> Unterstützung in avr-gcc?
Fände ich persönlich eine tolle Sache, besonders für nicht so versierte 
Nutzer sicher eine Bereicherung, sollte dann natürlich gegenüber echtem 
float wenn möglich platzsparender sein dann wäre es meiner Meinung nach 
eine Bereicherung.

von amateur (Gast)


Lesenswert?

@Läubi

... und Waschen und Bügeln sollte sie auch noch können.

Die Hauptdaseinsberechtigung der Fließkommazahlen ist ihre Kompaktheit.

von Rolf M. (rmagnus)


Lesenswert?

Mit avr-g++ könnte man sich auch eine Fixed-Point-Klasse basteln, die 
sich annähernd wie ein eingebauter Datentyp verhält, und das ganz ohne 
irgendwelche Änderungen am Compiler. Wenn man's als Template definiert, 
auch mit wählbarer Zahl an Vor- und Nachkommastellen.
Ich hatte sowas mal angefangen, aber mangels persönlicher Notwendigkeit 
nicht fertiggemacht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
> Mit avr-g++ könnte man sich auch eine Fixed-Point-Klasse basteln,
> die sich annähernd wie ein eingebauter Datentyp verhält,

Mit der gleichen Effizient wird man das kaum hinbekommen.

> und das ganz ohne irgendwelche Änderungen am Compiler.
> Wenn man's als Template definiert, auch mit wählbarer Zahl an
> Vor- und Nachkommastellen.  Ich hatte sowas mal angefangen,
> aber mangels persönlicher Notwendigkeit nicht fertiggemacht.

Ich habe bisher noch keine solche Implementierung gesehen.  Es wird 
immer behauptet, es sei einfach und naheliegend.

Ich behaupte jetze einfach mal, in C++ ist das nicht naheliegend.

Wie würde zB eine einfache Klasse / Template konkret aussehen, die 
folgenden Code mit der gleichen Effizienz wie avr-gcc implementiert?
1
#include <stdfix.h>
2
3
const __flash accum offset[] = { 1.2k, -3.45k }; 
4
5
sat accum add_offset (sat accum a, unsigned i)
6
{
7
    return a + offset[i];
8
}

Und von mir aus auch mit 1/4 der Performance...  avr-gcc brauch dafür 26 
bytes Code (ATmega8); Funktionsaufrufe werden nicht benötigt.

Vor allem habe ich keine offensichtliche Lösung gefunden für

- Literale wie 1.23

- Solche Objekte (Lookup-Tabellen!) in den Flash legen

- Arithmetik wie Multiplikation oder saturierte Multiplikation ohne
  den nächstbreiteren Typ zu brauchen.

- Auch nur halbwegs so effizient zu sein wie avr-gcc ohne Assembler
  zu verwenden.  Selbst bei Verwendung von Assembler wird sich kaum
  jemand den Wolf machen wollen...

Auch Implementierungen wie libfixmath (C99) machen gegen avr-gcc keinen 
Stich.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Ich behaupte jetze einfach mal, in C++ ist das nicht naheliegend.
>
> Wie würde zB eine einfache Klasse / Template konkret aussehen, die
> folgenden Code mit der gleichen Effizienz wie avr-gcc implementiert?
>
1
> #include <stdfix.h>
2
> 
3
> const __flash accum offset[] = { 1.2k, -3.45k };
4
> 
5
> sat accum add_offset (sat accum a, unsigned i)
6
> {
7
>     return a + offset[i];
8
> }
>
> Und von mir aus auch mit 1/4 der Performance...  avr-gcc brauch dafür 26
> bytes Code (ATmega8); Funktionsaufrufe werden nicht benötigt.

Zum Vergleich: Hierist der Code vom avr-gcc:
1
add_offset:
2
  push r16
3
  push r17
4
/* prologue: function */
5
/* frame size = 0 */
6
/* stack size = 2 */
7
.L__stack_usage = 2
8
  lsl r20
9
  rol r21
10
  lsl r20
11
  rol r21
12
  subi r20,lo8(-(offset))
13
  sbci r21,hi8(-(offset))
14
  movw r30,r20
15
  lpm r16,Z+
16
  lpm r17,Z+
17
  lpm r18,Z+
18
  lpm r19,Z
19
  add r22,r16
20
  adc r23,r17
21
  adc r24,r18
22
  adc r25,r19
23
  brvc 0f
24
  ldi r25,0x80
25
  cp r19,r25
26
  sbc r24,r24
27
  sbci r25,0
28
  mov r22,r24
29
  mov r23,r24
30
  0:
31
/* epilogue start */
32
  pop r17
33
  pop r16
34
  ret

von Yalu X. (yalu) (Moderator)


Lesenswert?

Johann L. schrieb:
> Wie sinvoll  unsinnig  überflüssig wäre Fixed-Point Unterstützung in
> avr-gcc?

Ich fände so etwas recht nützlich. Interessant wäre insbesondere die
32-Bit-Fixed-Point-Arithmetik, weil hier bei der Implementierung in
Standard-C der für Zwischenergebnisse benötigte nächstgrößere Integer-
typ 64 Bit breit ist, den man sich auf dem AVR nicht unbedingt antun
möchte.

> Eine solche auf ISO/IEC TR 18037 "Emdedded-C" basierende Unterstützung
> war für avr-gcc 4.8 geplant

Im TR sind ja die Anzahl der Nachkommabits bei den fract-Typen und die
Anzahl der Vor- und Nachkommabits bei den accum- und sat-Typen nicht
genau festgelegt. Welche Formate würden denn vom AVR-GCC unterstützt
werden?

> • Einfaches Lesen aus dem Flash

Bedeutet das, dass die "named adress spaces" aus dem TR implementiert
würden, so dass man auch beliebige andere const-Variablen ohne
pgm-*-Aufrufe direkt aus dem Flash lesen kann? Damit würde einer der
Nachteile, die der GCC gegenüber ander AVR-C-Compilern (z.B. IAR)
hat, beseitigt werden.

> #include <stdfix.h>
>
> const __flash accum offset[] = { 1.2k, -3.45k };
>
> sat accum add_offset (sat accum a, unsigned i)
> {
>     return a + offset[i];
> }
>
>
> avr-gcc brauch dafür 26 bytes Code (ATmega8)

Gerade bei saturierender Arithmetik bringt natürlich eine Implementie-
rung als Spracherweiterung deutliche Effizienzvorteile, da dann das
Overflow- und andere Prozessorstatusbits genutzt werden können, auf
die man von C aus keinen direkten Zugriff hat.

> Zum Vergleich: Hierist der Code vom avr-gcc:
> ...

Das sieht schon sehr nach dem Optimum aus, sowohl was die saturierende
Arithmetik als auch die direkte Einbindung der Flash-Zugriffe betrifft.

Das heißt aber ja auch, dass die Implementierung der Erweiterungen
schon sehr fortgeschritten ist. Wäre es da nicht sinnvoll, diese auf
jeden Fall offziell zu machen, auch wenn sich hier vielleicht nicht
jeder zu Begeisterungsstürmen hinreißen lässt?

von amateur (Gast)


Lesenswert?

Bitte nicht mit Gewalt das Rad neu erfinden.
Es gibt bereits freie Bibliotheken mit Festkommaarithmetik.
Ob fertig für die AVR-Serie weiß ich nicht.
Als Sourcecode (C): Auf jeden Fall.
Der Name ist mir allerdings derzeit nicht geläufig.

von Axel S. (a-za-z0-9)


Lesenswert?

Johann L. schrieb:
> Eine Frage die Allgemeinheit:
>
> Wie sinvoll  unsinnig  überflüssig wäre Fixed-Point Unterstützung in
> avr-gcc?

Es mag ungenutzte Compilerfeatures geben - unsinnig oder überflüssig 
wären sie deswegen noch lange nicht.

Im Moment behelfe ich mir in diesen Fällen mit Assembler, aber in der 
Tat wäre Anwendungscode in gewohnter Operatorschreibweise schöner. In 
C++ habe ich sowas früher auch gemacht, aber da war es für Bignums bzw. 
Brüche aus Bignums. Für kurze Festkommaarithmetik wäre der C++ typische 
Overhead zu groß um noch sinnvoll (besser als Fließkomma) zu sein.

Langer Rede kurzer Sinn: ja bitte!

> Eine solche auf ISO/IEC TR 18037 "Emdedded-C" basierende Unterstützung
> war für avr-gcc 4.8 geplant und ist in ähnlicher Form bereits in den
> Atmel-Tools basierend auf avr-gcc 4.6 enthalten.

Google findet nur Bezahlquellen für den Standard. Gibts nicht irgendwo 
einen Draft oder zumindest eine informelle Beschreibung zum freien 
Download?


XL

von Axel S. (a-za-z0-9)


Lesenswert?

amateur schrieb:
> Bitte nicht mit Gewalt das Rad neu erfinden.
> Es gibt bereits freie Bibliotheken mit Festkommaarithmetik.

[ ] Du hast die Frage verstanden

Es geht um arithmetische Typen, die kürzeren und schnelleren Code 
erlauben als Fließkomma. Da kann eine Bibliothek aus mehreren Gründen 
nicht mit eingebauten Typen mithalten. Weder beim Komfort 
(Operatorüberladung) noch bei Codegröße/Geschwindigkeit (call frames 
etc.)


XL

von amateur (Gast)


Lesenswert?

Nimm den Dreisatz: Google (Fixed-Point)-> Wikipedia Links (am 
Seitenende)->
und Du landest bei: z.B. libfixmath
Würde mich auch wundern, wenn es bei sourceforge.net nix gäbe.
Dauerte weniger als eine Minute.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Axel Schwenke schrieb:

> Google findet nur Bezahlquellen für den Standard. Gibts nicht irgendwo
> einen Draft oder zumindest eine informelle Beschreibung zum freien
> Download?

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

amateur schrieb:
> Nimm den Dreisatz: Google (Fixed-Point)-> Wikipedia Links (am
> Seitenende)->
> und Du landest bei: z.B. libfixmath

Bevor du da weiter drauf herumreitest, lies dir bitte durch, warum
das keine optimale Variante ist:

Beitrag "Re: Fixed-Point Support in avr-gcc?"

von Konrad S. (maybee)


Lesenswert?

Fixed-Point-Unterstützung direkt vom avr-gcc fände ich ganz nett. Es 
würde (mir) hin und wieder Denk-Zeit sparen für andere Dinge.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Johann L. schrieb:
>> Wie sinvoll / unsinnig / überflüssig wäre Fixed-Point Unterstützung in
>> avr-gcc?
>
> Ich fände so etwas recht nützlich. Interessant wäre insbesondere die
> 32-Bit-Fixed-Point-Arithmetik, weil hier bei der Implementierung in
> Standard-C der für Zwischenergebnisse benötigte nächstgrößere Integer-
> typ 64 Bit breit ist, den man sich auf dem AVR nicht unbedingt antun
> möchte.

Die Basisarithmetik ist vorhanden; die saturierenden 32-Bit 
Multiplikation und Division ist allerdings nicht Assembler-Optimiert und 
offen in C codiert (libgcc).  Wie bei der 64-Bit Arithmetik auch, 
besteht natürlich die Möglichkeit, die Anwendung gegen eigene 
Implementierungen zu linken.

>> Eine solche auf ISO/IEC TR 18037 "Emdedded-C" basierende Unterstützung
>> war für avr-gcc 4.8 geplant
>
> Im TR sind ja die Anzahl der Nachkommabits bei den fract-Typen und die
> Anzahl der Vor- und Nachkommabits bei den accum- und sat-Typen nicht
> genau festgelegt. Welche Formate würden denn vom AVR-GCC unterstützt
> werden?

http://gcc.gnu.org/wiki/avr-gcc#Fixed-Point_Support

>> • Einfaches Lesen aus dem Flash
>
> Bedeutet das, dass die "named adress spaces" aus dem TR implementiert
> würden, so dass man auch beliebige andere const-Variablen ohne
> pgm-*-Aufrufe direkt aus dem Flash lesen kann?

Nicht würden.  Die sind bereits seit ca. 1 Jahr (2012-03-22) 
releast:

http://gcc.gnu.org/gcc-4.7/changes.html

>> #include <stdfix.h>
>>
>> const __flash accum offset[] = { 1.2k, -3.45k };
>>
>> sat accum add_offset (sat accum a, unsigned i)
>> {
>>     return a + offset[i];
>> }
>>
>>
>> avr-gcc brauch dafür 26 bytes Code (ATmega8)
>
> Gerade bei saturierender Arithmetik bringt natürlich eine Implementie-
> rung als Spracherweiterung deutliche Effizienzvorteile, da dann das
> Overflow- und andere Prozessorstatusbits genutzt werden können, auf
> die man von C aus keinen direkten Zugriff hat.

Selbst wenn man in AVR-Assembler erfahren ist, hat man hier ruckzuck 
falschen Code falls man nicht extrem aufpasst.

Es ist zum Beispiel nicht mehr egal, ob ein negativer Wert addiert oder 
ein positiver abgezogen wird.  Zudem werden evtl. Sonderbehandlungen für 
0x80 notwendig.  Zumindest wenn man die AVR-Instruktionen optimal nutzen 
will.

> Das heißt aber ja auch, dass die Implementierung der Erweiterungen
> schon sehr fortgeschritten ist. Wäre es da nicht sinnvoll, diese auf
> jeden Fall offziell zu machen, auch wenn sich hier vielleicht nicht
> jeder zu Begeisterungsstürmen hinreißen lässt?

Es basiert auf einer Implementierung von Sean D'Épagnier, die in den 
avr-atmel-gcc 4.6 eingeflossen ist.  Diese verwendet allerdings ein 
anderes Layout, z.b. s15.16 für Accum anstatt s16.15 wie es avr-gcc 4.8 
tut.

von Fabian O. (xfr)


Lesenswert?

Wäre es nicht sinnvoll, von Anfang an auch Typen mit expliziter Breite 
anzubieten, wie in stdint.h?
1
typedef short     _Fract fract8_t;
2
typedef           _Fract fract16_t;
3
typedef long      _Fract fract32_t;
4
typedef long long _Fract fract64_t;
5
6
typedef short     _Accum accum16_t;
7
typedef           _Accum accum32_t;
8
typedef long      _Accum accum64_t;

Ansonsten klingt das sehr praktisch, vor allem die eingebaute 
Saturierung. Schade ist halt, dass Code mit diesen Typen völlig 
unportabel wird. Aber gut, irgendwo muss man ja anfangen. Vielleicht 
findet es mit der Zeit ja Einzug in andere Compiler.

Ich selber würde es erstmal nur in kleinen Projekten einsetzen, in denen 
man viel Festkommarechnung benötigt und den Code ziemlich sicher nicht 
auf einer anderen Plattform wiederverwenden will.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Fabian O. schrieb:
> Wäre es nicht sinnvoll, von Anfang an auch Typen mit expliziter Breite
> anzubieten, wie in stdint.h?

> typedef long      _Accum accum64_t;

Es gibt 8 accum-Typen die 64 Bits breit sind:

signed long accum
unsigned long accum
sat signed long accum
sat unsigned long accum
signed long long accum
unsigned long long accum
sat signed long long accum
sat unsigned long long accum

Ausserdem ist accum zumindest per stdfix.h "standardisiert" und stdint.h 
gehört ganz offiziell zu C99.

> Schade ist halt, dass Code mit diesen Typen völlig
> unportabel wird. Aber gut, irgendwo muss man ja anfangen. Vielleicht
> findet es mit der Zeit ja Einzug in andere Compiler.

"Völlig" unportabel ist es nicht, zumindest innerhalb von GCC ist es 
portabel.  Und der deckt immerhin einiges an Silizium ab.

Portabilität ist aber nicht die Aufgabe des Compilers, der stellt 
zunächst nur Features zur Verfügung, die speziell für Maschinen mit 
(sehr) knappen Resoucren sinnvoll bis unentbehrlich sind.

Portabilität könnte man zB mittels Bibliotheken wie libfixmath 
erreichen, falls diese das Vorhandenseit / Nichtvorhandensein eines 
entsprechenden, nativen Fixedpoit-Supports herausfaktorisiert.

Das Interface wäre immer noch Portabel, nur die Innereien der Lib würden 
sich bei Verwendung eines anderen Compilers verbiegen.

Generell zur Portabilität: Wie Portabel sind denn AVR-Anwendungen? 
Laufen deine AVR-Anwendungen auf einem PC? Ohne Anpassungen?

Und was ist mit PROGMEM etc.  Das ist "nur" eine Optimierung, aber eine, 
ohne die man die AVR-Hardware nicht wirklich nutzen kann.

> Ich selber würde es erstmal nur in kleinen Projekten einsetzen, in denen
> man viel Festkommarechnung benötigt und den Code ziemlich sicher nicht
> auf einer anderen Plattform wiederverwenden will.

Bislang hab ich mir noch nicht den Wolf gemacht und Programme wie zB 
4000 Stellen von Pi mit ATtiny2313 nach Fixed portiert. Wäre als 
Vergleich / Arithmetik-Benchmark bestimmt interessant.

von Fabian O. (xfr)


Lesenswert?

Johann L. schrieb:
> Es gibt 8 accum-Typen die 64 Bits breit sind:
>
> signed long accum
> unsigned long accum
> sat signed long accum
> sat unsigned long accum
> signed long long accum
> unsigned long long accum
> sat signed long long accum
> sat unsigned long long accum

OK. War mir nicht bewusst, dass es eigene Typen für die saturierte 
Artithmetik gibt. Für signed und unsigned hätte ich in Anlehnung an 
stdint.h accum64_t und uaccum64_t vorgeschlagen. Nach dem gleichen 
Schema könnte man die saturierten Typen mit einem zusätzlichen "s" 
kennzeichnen:
1
typedef     signed   long _Accum accum64_t;
2
typedef     unsigned long _Accum uaccum64_t;
3
typedef sat signed   long _Accum saccum64_t;
4
typedef sat unsigned long _Accum suaccum64_t;

Der "unsymmetrische" long long accum tanzt eh aus der Reihe, dafür 
bräuchte man imo keinen alternativen Namen. Oder man nimmt meinetwegen 
accum64_48_t o.ä..

> Ausserdem ist accum zumindest per stdfix.h "standardisiert" und stdint.h
> gehört ganz offiziell zu C99.

Genau das finde ich inkonsequent: In der offiziellen stdint.h gibt es 
endlich Typen mit eindeutiger Länge und in der neuen stdfix.h fängt man 
wieder mit dem schwammigen "short, nichts, long, long long"-Kram an ...

> Portabilität könnte man zB mittels Bibliotheken wie libfixmath
> erreichen, falls diese das Vorhandenseit / Nichtvorhandensein eines
> entsprechenden, nativen Fixedpoit-Supports herausfaktorisiert.
>
> Das Interface wäre immer noch Portabel, nur die Innereien der Lib würden
> sich bei Verwendung eines anderen Compilers verbiegen.

Klar, nur hat man dann in C nicht mehr die natürliche Schreibweise in 
Ausdrücken, sondern muss wieder Makros bzw. Funktionsaufrufe nutzen. 
Vorteil wäre dann "nur" noch die höhere Geschwindigkeit und eventuell 
kompakterer Code.

> Generell zur Portabilität: Wie Portabel sind denn AVR-Anwendungen?
> Laufen deine AVR-Anwendungen auf einem PC? Ohne Anpassungen?

Komplette Anwendungen natürlich nicht. Die Module oberhalb der 
Hardwareabstraktionsebene kann man allerdings unverändert in 
PC-Anwendungen einbauen, ja.

> Und was ist mit PROGMEM etc.  Das ist "nur" eine Optimierung, aber eine,
> ohne die man die AVR-Hardware nicht wirklich nutzen kann.

PROGMEM lässt sich immerhin portieren, indem man eine pgmspace.h mit 
Dummy-Implementierungen für die Makros und Funktionen anlegt. Mit der 
Festkomma-Arithmetik geht das leider nicht.

Aber versteh mich nicht falsch, ich habe absolut nichts dagegen, dass 
die Fixpoint-Arithmetik in avr-gcc eingebaut wird, ganz im Gegenteil. 
Ich würde es nur aus Portabilitätsgründen eben nicht in allen Projekten 
einsetzen, solange es nicht auch außerhalb des GCCs unterstützt wird.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Fabian O. schrieb:

> OK. War mir nicht bewusst, dass es eigene Typen für die saturierte
> Artithmetik gibt. Für signed und unsigned hätte ich in Anlehnung an
> stdint.h accum64_t und uaccum64_t vorgeschlagen. Nach dem gleichen
> Schema könnte man die saturierten Typen mit einem zusätzlichen "s"
> kennzeichnen:

Ja, hätte man. Ist aber nicht so. Die vorgeschlagenen typedefs sind ja 
auch nirdendwo standardisiert, was soll das also bringen?  Zudem liefern 
sie keine neue Funktionalität.  Und jeder kann sich selbst Typed 
definieren wenn er will.  Ausserdem wäre ein 32-Bit Typ in der 
Atmel-Toolchain ein anderer Typ und nicht binärkompatibel mit dem 
32-Bit-Typ im offiziellen avr-gcc.  Da ist ein "accum" noch portabler!

Im momentanen Stand der Implementierung geht es auch erst mal um 
Basisfunktionalität, nicht um Schnickschnack drumrum. Und auch nicht 
um Standardisierung; die ist nicht aufgabe von GCC, sondern der WGs der 
ISO.

von Peter D. (peda)


Lesenswert?

Johann L. schrieb:
> Wie sinvoll / unsinnig / überflüssig wäre Fixed-Point Unterstützung in
> avr-gcc?

Welche Anwendungen dafür hast Du denn?
Ich habe es bisher weder vermißt noch benötigt.

Float brauche ich nur für Ein-/Ausgaben und da ist der Mensch viel 
langsamer, die Rechenzeit also völlig wurscht.

Regelungen mache ich in integer, die ADCs und DACs verstehen ja auch nur 
integer, wozu also unnötig umwandeln.
Bei Bedarf denke ich mir für die Zwischenrechnungen (32 Bit) 1 Byte als 
Nachkommastelle.

Ohne wirklichen zwingenden Grund nutze ich keine nicht portablen 
Funktionen oder gar Assembler.

Ich amüsiere mich nur über Leute, die mit großem Aufwand an völlig 
unbedeutenden Stellen um einzelne Zyklen oder Bytes kämpfen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:

> Ich amüsiere mich nur über Leute, die mit großem Aufwand an völlig
> unbedeutenden Stellen um einzelne Zyklen oder Bytes kämpfen.

Heisst also konkret: avr-gcc ist git wie er ist und bedarf keiner 
weiteren Optimierungen oder Featues.

Schön :-)

Wie bei Thunderbird: Wird eingestapmft da perfekt und nicht mehr 
verbesserbar :-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Johann L. schrieb:
>> Bedeutet das, dass die "named adress spaces" aus dem TR implementiert
>> würden, so dass man auch beliebige andere const-Variablen ohne
>> pgm-*-Aufrufe direkt aus dem Flash lesen kann?
>
> Nicht würden.  Die sind bereits seit ca. 1 Jahr (2012-03-22)
> releast:
>
> http://gcc.gnu.org/gcc-4.7/changes.html

Jetzt bin ich von den Socken, das geht ja tatsächlich schon. Vielleicht
sollte ich beim nächsten Update mal die Release-Notes etwas aufmerksamer
durchlesen ;-)

>> Im TR sind ja die Anzahl der Nachkommabits bei den fract-Typen und die
>> Anzahl der Vor- und Nachkommabits bei den accum- und sat-Typen nicht
>> genau festgelegt. Welche Formate würden denn vom AVR-GCC unterstützt
>> werden?
>
> http://gcc.gnu.org/wiki/avr-gcc#Fixed-Point_Support

Die Halbe-Halbe-Aufteilung bei den Accum-Typen klingt vernünftig. Im TR
ist ja ein Minimum von 4 Vorkommabits vorgesehen, was aber gerade einmal
reicht, um 16 Zahlen aus [0,1) aufzuaddieren. Gut, dass sich der GCC
nicht auf dieses Minimum beschränkt.

Wenn ich am Wochenende die Zeit finde, werde ich mal ein 4.8er-Snapshot
saugen und ein Bisschen mit den Fixed-Point-Operationen herumspielen.

von Peter D. (peda)


Lesenswert?

Johann L. schrieb:
> Heisst also konkret: avr-gcc ist git wie er ist und bedarf keiner
> weiteren Optimierungen oder Featues.

Wer hat das behauptet?

Ich meinte ausschließlich den Anwender des Compilers.
D.h. im Quelltext möchte ich nicht kryptischen, unleserlichen, 
fehlerträchtigen, unportablen Inline-Assembler sehen, nur um 2 Zyklen 
oder 2 Words einzusparen.

Am Compiler gibt es durchaus noch Potential. Z.B. die Nutzung der 
Register R0,1 ändern, damit endlich mal die Würgarounds mit LPM, SPM, 
MUL und Interrupts entfallen können.

von Ralf G. (ralg)


Lesenswert?

Peter Dannegger schrieb:
> Johann L. schrieb:
>> Wie sinvoll / unsinnig / überflüssig wäre Fixed-Point Unterstützung in
>> avr-gcc?
>
> Welche Anwendungen dafür hast Du denn?
> Ich habe es bisher weder vermißt noch benötigt.

Das habe ich mir bei meinen Hobby-Programierniveau gar nicht getraut zu 
fragen. Würde mich aber auch mal interessieren.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> D.h. im Quelltext möchte ich nicht kryptischen, unleserlichen,
> fehlerträchtigen, unportablen Inline-Assembler sehen, nur um 2 Zyklen
> oder 2 Words einzusparen.

Genau daher ist ja die Implementierung von sowas wie fixed point
im Compiler der richtige Ansatz.  Hast du dir Johanns Beispiel
da oben mal angesehen?  Da ist nichts kryptisch oder unleserlich
dran.

von Carl D. (jcw2)


Lesenswert?

Hallo Johann,

ja, bitte bitte AVR-FIXPOINT einbauen.
Falls es zeitlich paßt :-)

Carl

von Peter D. (peda)


Lesenswert?

Jörg Wunsch schrieb:
> Hast du dir Johanns Beispiel
> da oben mal angesehen?

Welchen Beitrag meinst Du?
Wie gesagt, ich hatte bisher nicht die Notwendigkeit, andere als die 
Standardtypen zu verwenden.

Das Überlaufproblem ist mir auch aufgefallen. Ich habe dann mit dem 
16Bit-ADC-Wert alle Rechnungen 32Bit gemacht und zum Schluß für den DAC 
wieder auf 16Bit begrenzt.
Ein anders Problem hatte ich mit der Division, wenn der ADC 0 liefert. 
Ich habe dann einfach zum ADC-Wert 1 addiert.
Man muß bei Regelungen auch höllisch aufpassen, wo man signed und wo man 
unsigned rechnet.

Jörg Wunsch schrieb:
> Da ist nichts kryptisch oder unleserlich
> dran.

Das bezog sich nur auf die vielen Threads, wo immer gleich der Inline 
Assembler hervorgekramt wird, sobald im Listing ein Befehl zuviel 
auftaucht. War also etwas OT.

von Carl D. (jcw2)


Lesenswert?

schön an SAT wäre gerade im Embeded Bereich, daß z.B. 
Stellgrößen/interne Reglerwerte nie überlaufen und man deswegen das 
Regelverfahren als Quelltext schreibt und nicht die Umgehung der 
DatentypUnzulänglichkeiten.

von Peter D. (peda)


Lesenswert?

Carl Drexler schrieb:
> schön an SAT wäre gerade im Embeded Bereich, daß z.B.
> Stellgrößen/interne Reglerwerte nie überlaufen

Dann sollte das aber auch einstellbar sein. Z.B. wenn der DAC nur 10Bit 
hat, auf 0..1023.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Jörg Wunsch schrieb:
>> Hast du dir Johanns Beispiel
>> da oben mal angesehen?
>
> Welchen Beitrag meinst Du?

Beitrag "Re: Fixed-Point Support in avr-gcc?"

von Simon K. (simon) Benutzerseite


Lesenswert?

Das __flash mittlerweile eingebaut ist, ist gerade auch neu für mich :-O 
Danke dafür! Ich weiß noch, dass es da mal mehrere Diskussionen drum 
gab, aber wusste nicht, dass es mittlerweile Einzug gehalten hat. 
pgmspace.h ade?

Kommazahlen (Egal ob float oder fix) braucht man eher selten. Aber wenn, 
dann meist in Algorithmen und da wäre fixkomma schon eine praktische und 
brauchbare Sache.

Peter Dannegger schrieb:
> Bei Bedarf denke ich mir für die Zwischenrechnungen (32 Bit) 1 Byte als
> Nachkommastelle.

Und genau sowas könnte man mit einer offiziellen Implementierung eben 
vermeiden. Wo man sich dann bei deinem Code erst "reindenken" muss, wäre 
bei Verwendung von offiziellen Fixkomma Typen der Fall klar.

Aber ich sehe auch ein, dass es größtenteils Geschmackssache ist. Auch 
ich bin bisher mit manuellen Fixkomma Implementierungen gut zurecht 
gekommen. Einen nennenswerten Vorteil sehe auch ich hier nur bei 
Anfängern oder Nicht-Hardcore Programmierern. Die können die Vorteile 
von float benutzen mit der Geschwindigkeit von int :-)

von Malte S. (maltest)


Lesenswert?

Johann L. schrieb:
> Vor allem habe ich keine offensichtliche Lösung gefunden für
>
> - Literale wie 1.23

Wäre das nicht der klassische Anwendungsfall für die User Defined 
Literals in C++11?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Malte S. schrieb:
> Johann L. schrieb:
>> Vor allem habe ich keine offensichtliche Lösung gefunden für
>>
>> - Literale wie 1.23
>
> Wäre das nicht der klassische Anwendungsfall für die User Defined
> Literals in C++11?

Ich bin wirklich nicht vertraut mit C++.  Mehrere Anläufe, immer 
großartig gescheitert :-)

Von daher auch meine Frage auf Rolfs Aussage in

Rolf Magnus schrieb:

wie denn so ein C++ konkret aussieht.  Mit großer Wahrscheinlichkeit, 
liegt es an meinen bescheidenen C++ Kenntnissen.  Ein minimales 
Beispiel, das dem 3-Zeiler in C entspricht und nicht im kompletten 
Performance-Waterloo endet, würd ja schon reichen um es zu illustrieren.

Das kann doch soooo schwer nicht sein?

Oder doch?

Mein Versuch mit Literals endete zB im kompletten Code-Bloat.

Jedenfalls ist die Klasse damit (oder mit Konstruktoren) nicht-POD, kann 
also nicht ins Flash gelegt werden.

Lookup-Tabelle aufbauen? Njet! progmem- und section-Atribut (müssen) 
versagen.

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:

> wie denn so ein C++ konkret aussieht.  Mit großer Wahrscheinlichkeit,
> liegt es an meinen bescheidenen C++ Kenntnissen.  Ein minimales
> Beispiel, das dem 3-Zeiler in C entspricht und nicht im kompletten
> Performance-Waterloo endet, würd ja schon reichen um es zu illustrieren.

Genau da liegt das Problem.
Im Prinzip ist sowas in C++ nicht schwer zu machen. Aber es performant 
zu machen, ist eine ganz andere Sache. Denn im Compiler kannst du auch 
'schräge' Datentypen mit zb 24 Bit problemlos benutzen, was auf C++ 
Ebene so nicht geht.
Auch bei saturierter Arithmetik brauchen wir uns gar nicht weiter 
unterhalten. Da hast du auf Hochsprachenebene keine Chance, weil der 
Zugriff auf das Overflow-Flag fehlt. Das ist der Dolchstoss, mit dem 
einem hier jeder Assembler-Programmierer aussticht.

> Mein Versuch mit Literals endete zB im kompletten Code-Bloat.
>
> Jedenfalls ist die Klasse damit (oder mit Konstruktoren) nicht-POD, kann
> also nicht ins Flash gelegt werden.

Der Punkt ist mir noch nicht klar.
Ob eine Klasse ein POD ist oder nicht, hängt nicht davon ab, ob sie 
Konstruktoren hat oder nicht, sondern ausschliesslich davon, ob ihre 
Member-Variablen selber POD sind.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Johann L. schrieb:
>
>> wie denn so ein C++ konkret aussieht.  Mit großer Wahrscheinlichkeit,
>> liegt es an meinen bescheidenen C++ Kenntnissen.  Ein minimales
>> Beispiel, das dem 3-Zeiler in C entspricht und nicht im kompletten
>> Performance-Waterloo endet, würd ja schon reichen um es zu illustrieren.
>
> Genau da liegt das Problem.
> Im Prinzip ist sowas in C++ nicht schwer zu machen. Aber es performant
> zu machen, ist eine ganz andere Sache. Denn im Compiler kannst du auch
> 'schräge' Datentypen mit zb 24 Bit problemlos benutzen, was auf C++
> Ebene so nicht geht.

Die 3-Byte Typen machen hier keinen Unterschied, die werden bei der 
Fixed-Implementierung weder benötigt noch verwendet.  Diese Typen sind 
lediglich bei den 3-Byte Adressen als tiefhängendes Obst angefallen, 
spielen aber ansonsten keine Rolle im Compiler — ausser daß sie 
"öffentlich" gemacht wurden.


>> Mein Versuch mit Literals endete zB im kompletten Code-Bloat.
>>
>> Jedenfalls ist die Klasse damit (oder mit Konstruktoren) nicht-POD, kann
>> also nicht ins Flash gelegt werden.
>
> Der Punkt ist mir noch nicht klar.
> Ob eine Klasse ein POD ist oder nicht, hängt nicht davon ab, ob sie
> Konstruktoren hat oder nicht, sondern ausschliesslich davon, ob ihre
> Member-Variablen selber POD sind.

Der Knackpunkt ist jedenfalls: Sobald Konstruktion notwendig ist, kann 
das Ding nicht mehr im Flash (.progmem) liegen und wird nach .rodata 
oder sogar .data gelegt.

Alles andere würde bedeuten, daß der Compiler zur Compilezeit den Code 
der Konstruktors simulieren müsste, um zu wissen, was in Flash kommt. 
Und bei virtuellen Klassen ist es erst zur Laufzeit bekannt, was was 
ist.

Beispiel:
1
const char __attribute__((__progmem__)) var = "Hallo"[0];

Warum das nicht zur Compilezeit zu 'H' ausgewertet werden darf? Frag die 
C++ Experten...

von Rüdiger (Gast)


Lesenswert?

Da könnten die neuen constexpr-Konstruktoren helfen (welche auch überaus 
nützlich für die Berechnung von Baudraten-Registerwerten sind).

Solch eine C++-Implementierung könnte evtl. bei der Umsetzung von 
digitalen Filtern helfen, wo man zuweilen eine feinere Abstimmung 
zwischen Vor- und Nachkommazahlen braucht.

Gibt es für die stdfix.h eine brauchbare Einführungsseite? Welchen 
Vorteil bieten die __Accum-Typen? Wird bei denen die eigentliche 
Operation mit einer größeren Bitanzahl durchgeführt?

von Klaus W. (mfgkw)


Lesenswert?

oh, sehe den Thread jetzt erst durch die letzte Antwort - keine Ahnung, 
wie interessant die Fragen darin noch sind.

Johann L. schrieb:
> Wie sinvoll / unsinnig / überflüssig wäre Fixed-Point Unterstützung in
> avr-gcc?

Sicher sehr interessant, weil:
- (in C zumindest) viel besser lesbar als selbstgebautes
- hoffentlich effizienter und besser optimierbar als selbstgebautes

Schön wäre natürlich, wenn es eine Lösung gäbe, die halbwegs portabel 
bleibt in der Zukunft. Aber das wird natürlich Hoffnung bleiben...

Ein Ansatz dazu soll wohl ISO/IEC TR 18037:2008 gewesen sein. Kenne ich 
nicht näher, aber ist wohl sehr eingeschränkt bzgl. der Stellenzahlen.

Generell sehe ich eine Nützlichkeit aber eher für Leute, die sich für 
immer C++ verweigern.
Ich habe da weniger Scheu und nehme von C++ auch das, was mir nützlich 
erscheint, und bin dann schnell bei templates.


Johann L. schrieb:
> Johann L. schrieb:
>> Ich behaupte jetze einfach mal, in C++ ist das nicht naheliegend.
>>
>> Wie würde zB eine einfache Klasse / Template konkret aussehen, die
>> folgenden Code mit der gleichen Effizienz wie avr-gcc implementiert?
>>> #include <stdfix.h>
>>
>> const __flash accum offset[] = { 1.2k, -3.45k };
>>
>> sat accum add_offset (sat accum a, unsigned i)
>> {
>>     return a + offset[i];
>> } >
>> Und von mir aus auch mit 1/4 der Performance...  avr-gcc brauch dafür 26
>> bytes Code (ATmega8); Funktionsaufrufe werden nicht benötigt.
>
> Zum Vergleich: Hierist der Code vom avr-gcc:add_offset:
>   push r16
>   push r17
> /* prologue: function */
> /* frame size = 0 */
> /* stack size = 2 */
> .L__stack_usage = 2
>   lsl r20
>   rol r21
>   lsl r20
>   rol r21
>   subi r20,lo8(-(offset))
>   sbci r21,hi8(-(offset))
>   movw r30,r20
>   lpm r16,Z+
>   lpm r17,Z+
>   lpm r18,Z+
>   lpm r19,Z
>   add r22,r16
>   adc r23,r17
>   adc r24,r18
>   adc r25,r19
>   brvc 0f
>   ldi r25,0x80
>   cp r19,r25
>   sbc r24,r24
>   sbci r25,0
>   mov r22,r24
>   mov r23,r24
>   0:
> /* epilogue start */
>   pop r17
>   pop r16
>   ret

Ich hatte ja vor einiger Zeit schon mal etwas dazu in 
Beitrag "Festkommazahlen mit C++" geschrieben, was ich auch 
gelegentlich selbst verwende.
Zum Vergleich habe ich den letzten Stand ausgegraben. Leider lief der 
nicht mit avr-g++, weil da keine std::limits<> vorhanden sind.

Die habe ich schnell stillgelegt, weil sie hier nichts zur Sache tun, 
und habe sie spaßeshalber gegen deine Funktion add_offset() antreten 
lassen.
Jetzt ist es natürlich schwer, verschiedene Datentypen miteinander zu 
vergleichen.
Dein accum kenne ich jetzt nicht und habe einfach zum Vergleich eine 
Festkommazahl aus einer int16_t genommen, die mit 2⁴ skaliert wird, also 
das Komma 4 Stellen nach links geschoben (rechnet intern also in 1/16).
Damit kann man etwa 1.2 und 3.45 abdecken, wenn auch nicht exakt.

Auch kennen meine Templates aktuell keine Saturierung, was den Vergleich 
noch fragwürdiger macht.

Trotzdem als Orientierung, was der avr-g++ 4.7.2 aus dieser Funktion 
macht:
1
...
2
#include "fixpoint/fixpoint.h"
3
4
typedef Anyware::fixpoint< int16_t, int16_t, 4 >    accum;
5
6
const accum offset[] = { accum( 120, 100 ), accum( -345, 100 ) };
7
8
accum add_offset ( const  accum &a, unsigned i )
9
{
10
    return a + offset[i];
11
}
12
...


1. Ohne Optimierung kommt heraus
1
...
2
.global  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj
3
  .type  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj, @function
4
_Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj:
5
  push r28
6
  push r29
7
  rcall .
8
  rcall .
9
  rcall .
10
  in r28,__SP_L__
11
  in r29,__SP_H__
12
/* prologue: function */
13
/* frame size = 6 */
14
/* stack size = 8 */
15
.L__stack_usage = 8
16
  std Y+2,r25
17
  std Y+1,r24
18
  std Y+4,r23
19
  std Y+3,r22
20
  std Y+6,r21
21
  std Y+5,r20
22
  ldd r24,Y+5
23
  ldd r25,Y+6
24
  lsl r24
25
  rol r25
26
  mov r20,r24
27
  mov r21,r25
28
  subi r20,lo8(-(_ZL6offset))
29
  sbci r21,hi8(-(_ZL6offset))
30
  ldd r24,Y+1
31
  ldd r25,Y+2
32
  ldd r18,Y+3
33
  ldd r19,Y+4
34
  mov r22,r18
35
  mov r23,r19
36
  rcall _ZNK7Anyware8fixpointIiiLi4ELb1EEplERKS1_
37
  ldd r24,Y+1
38
  ldd r25,Y+2
39
/* epilogue start */
40
  adiw r28,6
41
  in __tmp_reg__,__SREG__
42
  cli
43
  out __SP_H__,r29
44
  out __SREG__,__tmp_reg__
45
  out __SP_L__,r28
46
  pop r29
47
  pop r28
48
  ret
49
.size  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj, .-_Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj
50
...

2. Mit -Os und -O3 sieht es erwartungsgemäß besser aus:
1
...
2
.global  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj
3
  .type  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj, @function
4
_Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj:
5
/* prologue: function */
6
/* frame size = 0 */
7
/* stack size = 0 */
8
.L__stack_usage = 0
9
  mov r30,r24
10
  mov r31,r25
11
  std Z+1,__zero_reg__
12
  st Z,__zero_reg__
13
  lsl r20
14
  rol r21
15
  subi r20,lo8(-(_ZL6offset))
16
  sbci r21,hi8(-(_ZL6offset))
17
  mov r30,r22
18
  mov r31,r23
19
  ld r18,Z
20
  ldd r19,Z+1
21
  mov r30,r20
22
  mov r31,r21
23
  ld r20,Z
24
  ldd r21,Z+1
25
  add r18,r20
26
  adc r19,r21
27
  mov r30,r24
28
  mov r31,r25
29
  std Z+1,r19
30
  st Z,r18
31
  ret
32
  .size  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj, .-_Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj
33
...

Sieht also doch gar nicht so schlimm, aus - du hattest ja nur 1/4 der 
Effizienz der internen Lösung gefordert :-)

Natürlich ist es schwer, mit einer compilerinternen Lösung mitzuhalten 
(insbesondere können meine templates ja nur auf vorhandenen Datentypen 
aufsetzen mit 8/16/32/64 Bit, und prinzipiell nicht mit 24 Bi oder noch 
krummeren, solange der gcc sie nicht anbietet).
Aber so schlimm ist es dann doch nicht geworden, wie ich befürchtet 
hatte.

Aber wie gesagt: der Vergleich hinkt von vornherein, wenn man 
unterschiedliche Wortbreiten vergleicht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:
> Johann L. schrieb:
>> Johann L. schrieb:
>>> Ich behaupte jetze einfach mal, in C++ ist das nicht naheliegend.
>>>
>>> Wie würde zB eine einfache Klasse / Template konkret aussehen, die
>>> folgenden Code mit der gleichen Effizienz wie avr-gcc implementiert?
>>>> #include <stdfix.h>
>>>
>>> const __flash accum offset[] = { 1.2k, -3.45k };
>>>
>>> sat accum add_offset (sat accum a, unsigned i)
>>> {
>>>     return a + offset[i];
>>> } >
>>> Und von mir aus auch mit 1/4 der Performance...  avr-gcc brauch dafür 26
>>> bytes Code (ATmega8); Funktionsaufrufe werden nicht benötigt.
>>
>> Zum Vergleich: Hierist der Code vom avr-gcc:add_offset:
>>   push r16
>>   push r17
>> /* prologue: function */
>> /* frame size = 0 */
>> /* stack size = 2 */
>> .L__stack_usage = 2
>>   lsl r20
>>   rol r21
>>   lsl r20
>>   rol r21
>>   subi r20,lo8(-(offset))
>>   sbci r21,hi8(-(offset))
>>   movw r30,r20
>>   lpm r16,Z+
>>   lpm r17,Z+
>>   lpm r18,Z+
>>   lpm r19,Z
>>   add r22,r16
>>   adc r23,r17
>>   adc r24,r18
>>   adc r25,r19
>>   brvc 0f
>>   ldi r25,0x80
>>   cp r19,r25
>>   sbc r24,r24
>>   sbci r25,0
>>   mov r22,r24
>>   mov r23,r24
>>   0:
>> /* epilogue start */
>>   pop r17
>>   pop r16
>>   ret

> Dein accum kenne ich jetzt nicht und habe

http://gcc.gnu.org/wiki/avr-gcc#Fixed-Point_Support

> Trotzdem als Orientierung, was der avr-g++ 4.7.2 aus dieser Funktion
> macht:
>
1
> ...
2
> #include "fixpoint/fixpoint.h"
3
> 
4
> typedef Anyware::fixpoint< int16_t, int16_t, 4 >    accum;
5
> 
6
> const accum offset[] = { accum( 120, 100 ), accum( -345, 100 ) };
7
> 
8
> accum add_offset ( const  accum &a, unsigned i )
9
> {
10
>     return a + offset[i];
11
> }
12
> ...
13
>

> 2. Mit -Os und -O3 sieht es erwartungsgemäß besser aus:
>
1
> ...
2
> .global  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj
3
>   .type  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj, @function
4
> _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj:
5
> /* prologue: function */
6
> /* frame size = 0 */
7
> /* stack size = 0 */
8
> .L__stack_usage = 0
9
>   mov r30,r24
10
>   mov r31,r25
11
>   std Z+1,__zero_reg__
12
>   st Z,__zero_reg__
13
>   lsl r20
14
>   rol r21
15
>   subi r20,lo8(-(_ZL6offset))
16
>   sbci r21,hi8(-(_ZL6offset))
17
>   mov r30,r22
18
>   mov r31,r23
19
>   ld r18,Z
20
>   ldd r19,Z+1
21
>   mov r30,r20
22
>   mov r31,r21
23
>   ld r20,Z
24
>   ldd r21,Z+1
25
>   add r18,r20
26
>   adc r19,r21
27
>   mov r30,r24
28
>   mov r31,r25
29
>   std Z+1,r19
30
>   st Z,r18
31
>   ret
32
>   .size  _Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj, 
33
> .-_Z10add_offsetRKN7Anyware8fixpointIiiLi4ELb1EEEj
34
> ...
35
>
>
> Sieht also doch gar nicht so schlimm, aus - du hattest ja nur 1/4 der
> Effizienz der internen Lösung gefordert :-)

Im C-Beispiel ist die Berechnung mit 32 Bit: accum ist Q-Format s16.15, 
d.h. 1 Vorzeichenbit, 16 Bits vor dem Komma und 15 danach.

Zudem saturiert der Code im C-Beispiel, d.h. 40000 + 40000 läüft nicht 
über zu einem negativen Wert sondern bleibt beim Maximum, also knapp 
65535, stehen.

Diese Saturiereung geschieht ohne (inter) mit 64 Bit zu rechnen.

Was mit an der C++ Lösung nicht gefällt ist dass die Konstanten als int 
angegeben werden, d.h. es ist nicht ersichtlich, welchen Wert "120" im 
Endeffekt hat.

Dritter Nachteil ist, dass die Konstanten in der Lookuop-Tabelle nicht 
im Flash stehen, und da bekommt man sie auch mit progmem nicht hin, denn 
dein accum-Typ ist kein POD (pretty old data).

Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.
Bitte reduzieren Sie die Anzahl der Zitatzeilen.

von Klaus W. (mfgkw)


Lesenswert?

Johann L. schrieb:
> Was mit an der C++ Lösung nicht gefällt ist dass die Konstanten als int
> angegeben werden, d.h. es ist nicht ersichtlich, welchen Wert "120" im
> Endeffekt hat.

Das hängt natürlich davon ab, welche Konstruktoren man spendiert.

In meiner Implementation gibt es davon 2:
a) Initialisierung mit einer Gleitkommazahl
b) wie hier mit 2 ganzen Zahlen, deren Quotient dann den Wert ergibt 
(120,100) ergibt also 1.20

Wenn man letzteren verwendet, vermeidet man prinzipiell jede 
Gleitkommarechnung zur Laufzeit.
Der erstere kann das vermeiden, wenn der Compiler schon mitdenkt udn 
gleich daraus den richtigen ganzen Werte macht. Ich gehe davon aus, daß 
der gcc das schafft, habe es aber nicht getestet.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.