www.mikrocontroller.net

Forum: GCC AVRGCC: Konstanten optimieren


Autor: Michael H. (overthere)
Datum:

Hallo,

ich habe das Problem, dass der GCC 2 Konstanten teilen soll. Diese
rechnet er aber nicht vorher aus, sondern will diese während der
Laufzeit ausrechnen. Wie bekomme ich den GCC dazu, diese doch bitte
vorher auszurechen?

======
void highvoltage_control(void){
  unsigned int voltage;

  // Hole aktuelle Spannung
  voltage=adc_read(ADC_supplyvoltageref);
  // Multipliziere mit 64, rechne koeffizenten aus, und gebe den auf
  // das Timer2 register.
  OCR2=(voltage<<6)/(voltage+((HIGHVOTLAGE_plus)/(HIGHVOTLAGE_SUPPLY_resistor_divider)));
}======

Es geht um die letzen 2 Konstanten. Die könnte er ja ganz bequem vorher
ausrechen. Nur wie bringe ich ihn dazu?

Vielen Dank für Eure Hilfe!

Michael
Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Michael H. schrieb:

> Es geht um die letzen 2 Konstanten. Die könnte er ja ganz bequem vorher
> ausrechen. Nur wie bringe ich ihn dazu?

Wie und wo sind deine Konstanten definiert
Auf welcher Stufe läuft der Optimizer
Autor: A. K. (prx)
Datum:

Wie sind die Konstanten definiert? Bitte Quellcode, ggf. mitsamt dem
Schreibfehler.
Autor: Michael H. (overthere)
Datum:

Die Defines:
=========================
// ADC adress of the supplyvoltage
#define ADC_supplyvoltageref 3
// ADC adress of the highmosfet voltage
#define ADC_highmosfet 6

// Equal reference value that is added to the supplyvoltage val
#define HIGHVOTLAGE_plus 10240
// Tollerance that is substaceted from the actual val
#define HIGHVOLTAGE_tol 100

// Hardware definded voltage divider (Supply voltage)
#define HIGHVOTLAGE_SUPPLY_resistor_divider 13
// Hardware definded voltage divider (High voltage)
#define HIGHVOTLAGE_STEPUP_resistor_divider 21
=========================

Optimierung ist auf size. (Also -Os)
Autor: A. K. (prx)
Datum:

Und was kommt dabei heraus, d.h. was genau ist falsch?

Hab's grad mit avr-gcc 4.3.3 probiert und es kommt genau das erwartete
raus, ein Shift und eine Division.
Autor: Michael H. (overthere)
Datum:

Ich habe auch GCC 3.4.4:
=======================================
avr-gcc (GCC) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is
NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
=======================================

Auchtsch! Oh mein Gott, war ich blind! Der GCC macht es richtig, der
rechnet ja eine aus, die man nicht vorher ausrechnen kein.

Sorry GCC, sorry Leute, dass ich euch belästigt habe, dass war ein
Doofheitsfehler wie er im Buche steht.

Gebe es aber nicht noch eine Möglichkeit, die Division zu vermeiden und
den Hardware Multiplizierer zu Nutzen?
Autor: A. K. (prx)
Datum:

Klar doch. Mit dem Kehrwert multiplizieren. Klingt aber einfacher als es
ist, weil ganzzahlig etwas haarig. Soll heissen: mit (Kehrwert*(2**N))
multiplizieren, möglichst ohne Überlauf, und dann durch (2**N)
dividieren. Das Ergebnis liegt ggf. um eins daneben, was hier aber wohl
nicht so tragisch sein dürfte.
Autor: Michael H. (overthere)
Datum:

Sorry, aber ich kapier das gerade irgendwie nicht.

Könntest du mir das anhand eines Beispiels erklären?

Danke

Michael
Autor: A. K. (prx)
Datum:

Schema:
x / 3
ersetzen durch
(x * (65536/3)) / 65536
Wenn's geht in vorzeichenloser Rechnung.
Autor: Michael H. (overthere)
Datum:

okay, danke... verstanden...
Autor: Teiler (Gast)
Datum:

>Schema:
>x / 3
>ersetzen durch
>(x * (65536/3)) / 65536

d.h. Du optimierst von einer Division auf eine Multiplikation und
zwei Divisionen? Na dann Mahlzeit!
Autor: A. K. (prx)
Datum:

Na dann schau mal rein, was ein Compiler bei eingeschalteter Optimierung
daraus macht. Dir ist offensichtlich entgangen, dass die eine Division
bereits vom Compiler und die andere durch einfache Registerverschiebung
erledigt wird.
Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Teiler schrieb:
>>Schema:
>>x / 3
>>ersetzen durch
>>(x * (65536/3)) / 65536
>
> d.h. Du optimierst von einer Division auf *eine Multiplikation und*
> zwei Divisionen? Na dann Mahlzeit!

Die eine Division ist konstant und wird bereits vom Compiler erledigt.
Die andere Division ist eine Division durch eine 2-er Potenz und kann
deaher mittels Schieben oder bei besonderen Zahlen durch 'schrägen'
Bytezugriff ins Ergebnis erledigt werden.

Multiplikation kann mit Hilfe der Hardware-Multiplikation erledigt
werden.

D.h. Die Optimierung lautet:
Von einer Software-Division auf
* eine Hardwaremultiplikation
* und ein paar Schiebebefehle (in dem Fall ist es noch nicht mal
  ein Schiebebefehl, sondern vom 32 Bit Ergebnis werden die unteren
  16 Bit verworfen).

Das ist doch nicht schlecht!
Autor: Teiler (Gast)
Datum:

OK. Das ist wahrlich nicht schlecht. :-)

Mein Kopfoptimierer hat das halt leider nicht wegoptimiert und somit war
ich ein wenig verwirrt.
Autor: Master Snowman (snowman)
Datum:

ich bin durch die suchfunktion auf diesen thread gestossen, weil ich
auch oft x / 10 rechnen muss...

>Schema:
>x / 3
>ersetzen durch
>(x * (65536/3)) / 65536

nun, wenn ich das ganzzahlig und mit x = 12 nachrechne, funktioniert das
aber nicht...
Autor: Martin Thomas (mthomas) (Moderator) Benutzerseite
Datum:

Master Snowman schrieb:
> ich bin durch die suchfunktion auf diesen thread gestossen, weil ich
> auch oft x / 10 rechnen muss...

*1/10 ist schon ziemlich oft durchgekaut. Siehe z.B. avrfreak
Tutorial-Forum, http://www.cs.uiowa.edu/~jones/bcd/divide.html , SuFu

>>Schema:
>>x / 3
>>ersetzen durch
>>(x * (65536/3)) / 65536
>
> nun, wenn ich das ganzzahlig und mit x = 12 nachrechne, funktioniert das
> aber nicht...

Hälfte des Divisors zum Dividenden addieren
Autor: A. K. (prx)
Datum:

Master Snowman schrieb:

> nun, wenn ich das ganzzahlig und mit x = 12 nachrechne, funktioniert das
> aber nicht...

Ich hatte davor selbst schon geschrieben, dass das Ergebnis einer
solchen Rechnung gern um 1 daneben liegt. Weil Rundung in anderer
Richtung.

Hier ging es um die Umrechnung eines ADC-Ergebnisses. Da ist ein solcher
Fehler oft zu verschmerzen.
Autor: Master Snowman (snowman)
Datum:

> Hälfte des Divisors zum Dividenden addieren
also korrekt:
x / 3
ersetzen durch
((x + 3/2) * (65536/3)) / 65536

danke :-)
Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Ganz interessant ist auch
   http://www.hackersdelight.org/divcMore.pdf

Johann

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net