richtig Runden nach Ganzzahl Operation

Gast #6898905
Lesenswert?

Hi,

ich habe folgenes Problem:

uint16_t erg=0, test=43;

erg=(test*1000/1440);

liefert: 29

Rückrechnung 29*1440/1000 =41,7

test kann was bis 55 sein.

Wie bekomme ich das genauer.

In diesem Beispiel wäre 30 als "Ergebnis" genauer. ->43,2

Wie runde ich mit wenig Aufwand, damit es für alle Zahlen der Reihe bis 
55 besser passt?

Danke.

Maddin
(Firma: egal) #6898913
Lesenswert?

Jens schrieb:
> Wie runde ich mit wenig Aufwand, damit es für alle Zahlen der Reihe bis
> 55 besser passt?

Das ganze hat mit math. Runden überhaupt nichts zu tun. Du rechnest mit 
ganzen Zahlen und da es dort keine Nachkommastellen gibt werden diese 
quasi abgeschnitten und somit kann man da auch nichts mehr "runden".

Schau dir mal das an:
- https://www.mikrocontroller.net/articles/Festkommaarithmetik
Gast #6899082
Lesenswert?

Hallo,

das was du brauchst ist ein Trick aus der Festkommaarithmetik

1000/1440 ist etwa gleich 711/1024 (Unterschied in der 1/10000 Stelle)
und deshalb rechnets du besser

erg = test*711/1024

die Multiplikation test*711 läuft normal
die Division .../1024 durch rechtsschiften

und mit Runden auf eine halbe Stelle ist es dann

erg = (test*711 + 256)/1024

Vorsicht: mit uint16_t auf Zahlenüberlauf achten

Gruss
Gast #6899152
Lesenswert?

Stefan schrieb:
> das was du brauchst ist ein Trick aus der Festkommaarithmetik
>
> 1000/1440 ist etwa gleich 711/1024 (Unterschied in der 1/10000 Stelle)
> und deshalb rechnets du besser
>
> erg = test*711/1024
>
> die Multiplikation test*711 läuft normal
> die Division .../1024 durch rechtsschiften

Den Trick predige ich, in der einen oder anderen Form, seit Jahr und 
Tag.
Inzwischen hab ich's aufgegeben.

Du fragst dich, was jetzt mit deinem Tipp passieren wird? Ich denke du 
willst das gar nicht wissen...

Wenn du Glück hast, großes Glück, dann fragt einer nach, wie Du auf 
711/1024 gekommen bist.

Von mir jedenfalls ein :+1:
Gast #6899176
Lesenswert?

Uwe B. schrieb:
> M.e.a. rundet ((43*1000) + (1440/2))/1440 richtig

Ja. Runden = vorher halben Teiler zu addieren. Negative Zahlen sind ein 
eigenes Thema!

Stefan schrieb:
> 1000/1440 ist etwa gleich 711/1024

Das ist besser, hat für sich gesehen mit dem Problem nichts zu tun. Es 
ist eine Optimierung. Wenn es funktioniert aber zu viel Platz oder 
Laufzeit braucht. Auch hier fällt man mit negativen Zahlen auf die Nase.
#6899190
Lesenswert?

Jens schrieb:
> Danke.
> Maddin

...und ward nicht mehr gesehen.
10/10 Ghost-TO-Punkte, leider nur
 2/10 Troll-Punkte

Zu Fractional-Arithmetic mit HildeK's Tipp hätte er sich schon mal 
wieder melden können. Viele Mikrocontroller unterstützen 
Fractional-Arithmetic im Befehlssatz, wie z.B. s16*s16-Multiplikation, 
die das Ergebnis um 15bits nach rechts geschoben wieder in ein 
16bit-Register schmeißt.

mfg mf
#6899213
Lesenswert?

jo schrieb:
> Stefan schrieb:
>> das was du brauchst ist ein Trick aus der Festkommaarithmetik
>>
>> 1000/1440 ist etwa gleich 711/1024 (Unterschied in der 1/10000 Stelle)
>> und deshalb rechnets du besser
>>
>> erg = test*711/1024
>>
>> die Multiplikation test*711 läuft normal
>> die Division .../1024 durch rechtsschiften
>
> Den Trick predige ich, in der einen oder anderen Form, seit Jahr und
> Tag.
> Inzwischen hab ich's aufgegeben.
>
> Du fragst dich, was jetzt mit deinem Tipp passieren wird? Ich denke du
> willst das gar nicht wissen...
>
> Wenn du Glück hast, großes Glück, dann fragt einer nach, wie Du auf
> 711/1024 gekommen bist.

Hallo,

die Frage wollte ich eigentlich stellen, bin aber selbst draufgekommen.
Verhältnisgleichung bzw. Normierung auf 1024. Nur fängt man sich damit 
nicht schon vorher einen Rundungsfehler ein bevor es überhaupt losgeht? 
Genau wären es ja 711,111.
Gast #6899339
Lesenswert?

Veit D. schrieb:
> Nur fängt man sich damit nicht schon vorher einen Rundungsfehler ein
> bevor es überhaupt losgeht?

Bei nur wenigen Aufgaben ist das schlimm. Und noch seltener ist dieser 
Fehler größer als z.b. ein off-by-one beim Teiler oder Rundungsoffset.

Wichtig ist nur die Priorität:

Erst richtig (runden), dann lesbar. Und effizient nur, wenn man es sich 
erlauben kann oder muss. Wenn 2 zahlen im Datenblatt oder Schaltplan 
stehen, sind die einfacher zu verstehen als wenn da zwei ganz andere 
sind.
Gast #6899351
Lesenswert?

Veit D. schrieb:
> Nur fängt man sich damit nicht schon vorher einen Rundungsfehler ein bevor
> es überhaupt losgeht?

Wenn dir der Rundungsfehler zu groß ist, musst du eine bessere Näherung 
für deine 1000/1440 verwenden.

Bei Annäherung durch 711/1024 weicht dein Faktor um 0,016 Prozent ab, 
bei 5689/8192 wäre es nur eine Abweichung von 0,002 Prozent, also ein 
Faktor 10 besser. Dafür schränkt sich bei gegebenem Variablentyp dein 
Zahlenbereich entsprechend ein.
#6899362
Lesenswert?

Wolfgang schrieb:
> Bei Annäherung durch 711/1024 weicht dein Faktor um 0,016 Prozent ab,
> bei 5689/8192 wäre es nur eine Abweichung von 0,002 Prozent, also ein
> Faktor 10 besser. Dafür schränkt sich bei gegebenem Variablentyp dein
> Zahlenbereich entsprechend ein.

Hier ist ausdrücklich ein Bereich bis 55 vorgegeben. Ob man den in 
diesem Fall halten kann, hängt davon ab, wie groß auf der Plattform int 
ist.
Gast #6899528
Lesenswert?

Bis x=55:
(x*89+62)/128

1  0,69  1,00
2  1,39  1,00
3  2,08  2,00
4  2,78  3,00
5  3,47  3,00
6  4,17  4,00
7  4,86  5,00
8  5,56  6,00
9  6,25  6,00
10  6,94  7,00
11  7,64  8,00
12  8,33  8,00
13  9,03  9,00
14  9,72  10,00
15  10,42  10,00
16  11,11  11,00
17  11,81  12,00
18  12,50  13,00
19  13,19  13,00
20  13,89  14,00
21  14,58  15,00
22  15,28  15,00
23  15,97  16,00
24  16,67  17,00
25  17,36  17,00
26  18,06  18,00
27  18,75  19,00
28  19,44  19,00
29  20,14  20,00
30  20,83  21,00
31  21,53  22,00
32  22,22  22,00
33  22,92  23,00
34  23,61  24,00
35  24,31  24,00
36  25,00  25,00
37  25,69  26,00
38  26,39  26,00
39  27,08  27,00
40  27,78  28,00
41  28,47  28,00
42  29,17  29,00
43  29,86  30,00
44  30,56  31,00
45  31,25  31,00
46  31,94  32,00
47  32,64  33,00
48  33,33  33,00
49  34,03  34,00
50  34,72  35,00
51  35,42  35,00
52  36,11  36,00
53  36,81  37,00
54  37,50  38,00
55  38,19  38,00

WS
Gast #6900037
Lesenswert?

Du hast einen Faktor von 1000/1440 = 0,694444...
Ich würde mit 0,694444 x 65536 = 45511 multiplizieren.

16 Bit x 16 Bit -> 32 Bit

Wirft man die unteren 16 Bit weg, rundet aber die verbleibenden
16 Bit um 1 auf, wenn das höchste weggeworfene Bit gesetzt ist,
kommt man auf sehr gut gerundete Ergebnisse.

Mit asm kein Problem.
Aber auch mit C gut machbar.

Gute Nacht!
Gast #6900245
Lesenswert?

Diese "Mul-Shift"-Vorgehensweise ist heute nicht mehr grundsätzlich zu 
empfehlen, da inzwischen öfters ein div direkt vom Controller 
unterstützt wird. Beim "Mul-Shift" müssen zum einen Überläufe verhindert 
werden und zum anderen könnte temporär ein größerer Datentyp nötig sein. 
Das alles wirkt sich negativ auf die Programmierzeit, Fehlergefahr und 
Laufzeit aus.
Gast #6900259
Lesenswert?

Wir haben alle mit den vom TO genannten Zahlen eine spezielle Lösung 
genannt, die für ihn funktioniert.
Man sollte die Rechnung auch etwas allgemeiner betrachten. So wäre das 
korrekt gerundete Ergebnis der der Ganzzahldivision erg=a*b/c dann:
erg = (a*b + c/2)/c

Näherungen mit schnelleren Bitshifts sind nur bei festen Zahlen b und c 
zu finden und vermutlich nicht mal bei allen.
Gast #6900340
Lesenswert?

Hallo,
1000/1440*128=88,88888.. = 89-1/9
Also
x*(89-1/9)+64 < x*89+64
Es kann also sein, dass (x×89+64)/128 als Ganzzahl im Argumentbereich zu 
gross ist. Deshalb versuche ich in der Rundung zu optimieren.
Das Ergebnis ist exakt im Argumentbereich und optimal umsetzbar in Zeit 
und Recourceneinsatz. Auch ohne mul und 32bit optimal zu lösen.

WS
Gast #6900356
Lesenswert?

HildeK schrieb:
> Wir haben alle mit den vom TO genannten Zahlen eine spezielle Lösung
> genannt, die für ihn funktioniert.

Im Gegenteil: Die meisten haben das Problem des TO (die Rundung) 
ignoriert oder beiläufig eingeflochten und sich auf die (unnötige) 
Optimierung der Division gestürzt. Und manche haben gar das Float-Fass 
geöffnet.

Und das, obwohl der TO im OP alle Informationen gegeben hat und es im 
Titel sehr präzise zusammengefasst hat:

> richtig Runden nach Ganzzahl Operation

Eine spezielle Lösung wäre die Wertetabelle. Bei 55 Werten von 8 Bit ein 
überschaubarer Aufwand mit perfekter (beliebiger) Genauigkeit.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren