Hallo, ich benutze einen float Wert in AVR-gcc. float x = 27.1285. Funktioniert perfekt in der Verbindung mit sprintf.... Jetzt möchte ich den Wert negieren ? (-27.1285) Aus der Doku weiss ich das mein float 32bit, also 4 byte gross ist. Muss ich jetzt das oberste Bit einfach auf 1 setzen ? das könnte ich ja mit: x |= 0x8000; Vielen Dank schon mal für einen Hinweis. Gruß Pete
:
Gesperrt durch Moderator
float x = 27.1285. x = 0 - x; oder x = d * -1; alles andere ist nicht wirklich Portable.
Peter schrieb: > float x = 27.1285. > > > x = 0 - x; > > oder > > x = d * -1; > > alles andere ist nicht wirklich Portable. Was ist denn an
1 | x = -x; |
nicht portabel?
Stefan Ernst schrieb: > Was ist denn an > > x = -x; > > nicht portabel? Manchmal liegt das Naheliegende so fern (nämlich einfach ein Minuszeichen vor die Variable zu schreiben) ;-) Wer's undurchschaubar mag, kann natürlich auch
1 | x = 1/(tan(atan(x)+M_PI/2)) |
schreiben. Das geht für fast alle x und stimmt wenigstens ungefähr ;-)
Ja, es geht aber auch x = e^(-i * pi + ln(x)) Müsste man nur noch die ganzen Funktionen aus der Mathe Bibliothek zusammensammeln ;)
> Aus der Doku weiss ich das mein float 32bit, also 4 byte gross ist. > x |= 0x8000; Damit würdest du z.B. das 15. Bit deiner 32-Bit-Zahl setzen... :-o
Lothar Miller schrieb:
> Damit würdest du z.B. das 15. Bit deiner 32-Bit-Zahl setzen... :-o
Noch schlimmer. Er würde die Gleitkommazahl in eine Ganzzahl
umwandeln und deren 15. Bit setzen.
Hier wäre noch die Variante für die, die es in C schreiben wollen, sich dabei aber auf die Zahlendarstellungsebene hinunter begeben wollen. ;-)
1 | double minus_x(double x) |
2 | {
|
3 | union { |
4 | double x; |
5 | unsigned char y[4]; |
6 | } u; |
7 | |
8 | u.x = x; |
9 | u.y[3] -= 0x80; |
10 | |
11 | return u.x; |
12 | }
|
A. K. schrieb:
> Da solltest du aber noch eine automatische Byteordererkennung anfügen.
Ich bin mir nicht einmal ganz sicher, ob der Algorithmus für
64-Bit-IEEE-854 der gleiche wäre. Dort ist der Exponent ja
größer.
Gilt so erst einmal nur für 32-bit-FP auf little-endian (AVR).
Der Exponent ist egal, weil das Vorzeichen in alle IEEE Formaten im höchsten Bit liegt. Aber die Byte-Order ist weniger einfach, wenn man auch jene schrägen Varianten berücksichtigt, in denen zwar das untere Byte aber das obere Wort vorneweg kommt.
A. K. schrieb: > Der Exponent ist egal, weil das Vorzeichen in alle IEEE Formaten im > höchsten Bit liegt. Ja, stimmt. > Aber die Byte-Order ist weniger einfach, Normalerweise gibt's das als Makro in einem Headerfile, aber das ist dann halt gerade bei AVR & Co nicht da. > wenn man > auch jene schrägen Varianten berücksichtigt, in denen zwar das untere > Byte aber das obere Wort vorneweg kommt.
1 | #if BYTE_ORDER == PDP_ENDIAN
|
:) Ich glaube, das hat dieser Tage nur noch historische Relevanz.
Oder noch etwas umständlicher:
1 | float a = -2.1; |
2 | void *ptr; |
3 | ptr = memset(ptr+3, 0x40 , 1); |
Ich denke mal, der Compiler wird am besten wissen, wie man x = -x; optimiert. Bei float irgendwelche kryptische, unlesbare und nicht portable Mikrooptimierungen hinzuschreiben, ist Blödsinn.
Jörg W. schrieb: > A. K. schrieb: >> wenn man >> auch jene schrägen Varianten berücksichtigt, in denen zwar das untere >> Byte aber das obere Wort vorneweg kommt. > >
1 | #if BYTE_ORDER == PDP_ENDIAN
|
> > :) > > Ich glaube, das hat dieser Tage nur noch historische Relevanz. Aber nur, weil man eine PDP-11 lieber in Assembler programmiert :) http://www.theregister.co.uk/2013/06/19/nuke_plants_to_keep_pdp11_until_2050/
Und was ist am o.g. portablen, offensichtlichen, der mathematischen Notation folgenden, nicht kürzer formulierbaren, optimalen Code erzeugenden
1 | float neg (float x) |
2 | {
|
3 | return -x; |
4 | }
|
auszusetzen? Macht avr-gcc zu
1 | neg: |
2 | subi r25,0x80 |
3 | ret |
Klaus schrieb: > Oder noch etwas umständlicher: Und Du brauchtest sieben Jahre, um das herauszufinden?