[C] int / float vermenigvuldiging

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • neliss
  • Registratie: Juni 2009
  • Laatst online: 17:11

neliss

h00t h00t!

Topicstarter
Goedenavond,

Ik ben bezig met het programmeren van een PIC microcontroller.
Nu zit ik met de situatie dat ik een integer zou willen vermenigvuldigen met 1.5 (wat dus een float is).
Zelf had ik gedacht dit te kunnen doen met:
code:
1
(int) (i * 1.5)

Maar helaas geeft dit niet het gewenste resultaat.
Ik kan niet goed zien wat er misgaat, omdat ik de waarde van het getal niet precies kan achterhalen omdat ik geen display heb voor het debuggen.
Ik kan alleen met ledjes het getal weergeven, maar deze blijven allemaal uit na de vermenigvuldiging (=0).
Wat wel goed gaat:
code:
1
2
3
(int) (i * 1)
of
(int) (i * 2)

Heeft iemand een idee wat er aan de hand kan zijn?

Acties:
  • 0 Henk 'm!

Verwijderd

Als je wilt vermenigvuldigen met 1.5 dan kun je ook de helft erbij optellen:

i = i + (i>>1);

Zo heb je geen floating point nodig.

Acties:
  • 0 Henk 'm!

  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
Bij kleine processoren zoals PIC microcontrollers is ondersteuning van float's niet vanzelfsprekend. Welke ontwikkelomgeving gebruik je?

Specialist in:
Soldeerstations
Oscilloscoop


Acties:
  • 0 Henk 'm!

  • TweakPino
  • Registratie: September 2005
  • Laatst online: 08:35
Waarschijnlijk gaat het mis omdat een PIC microcontroller geen floating point kan.
Wat (waarschijnlijk) wel werkt (in dit specifieke geval met 1.5) is dit:
code:
1
result = i + i/2

Of als dit ook nog niet wil werken, probeer dan dit:
code:
1
result = i + (i>>1)

(i>>1) is een bitshift van i met één plaats naar rechts, wat gelijk is aan i/2.

damn, wat reageert iedereen weer snel deze avond :P

[ Voor 7% gewijzigd door TweakPino op 01-05-2011 21:00 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Ik probeer floating point operaties altijd te vermijden, omdat ze sowieso meer tijd kosten (op een AVR in ieder geval) dan een integer operatie. Wat ik dus doe:

C:
1
2
3
int i = 10;

i = ((i * 10) * 15) / 10;


Daarmee komt i sowieso op 15 uit, wat hetzelfde is als:

C:
1
2
3
int i = 10;

i = i * 1.5;


Het is iets van 5 instructies meer, maar volgens mij nog een stuk sneller :).

Acties:
  • 0 Henk 'm!

  • neliss
  • Registratie: Juni 2009
  • Laatst online: 17:11

neliss

h00t h00t!

Topicstarter
Bedankt voor alle snelle reacties.
Ik heb er nooit bij stil gestaan dat de PIC waarschijnlijk geen floating points kan processen (zonder extra libraries), dit lijkt me de oorzaak van het probleem.
Er zijn genoeg slimme trucjes genoemd waarmee ik ook prima uit de voeten kan, bedankt hiervoor!

Ik werk trouwens met een PIC18F4550 in SourceBoost, voor degenen die hier conclusies uit kunnen trekken.

Acties:
  • 0 Henk 'm!

  • keejoz
  • Registratie: November 2008
  • Laatst online: 28-08 15:53
Verwijderd schreef op zondag 01 mei 2011 @ 21:50:
Ik probeer floating point operaties altijd te vermijden, omdat ze sowieso meer tijd kosten (op een AVR in ieder geval) dan een integer operatie. Wat ik dus doe:

C:
1
2
3
int i = 10;

i = ((i * 10) * 15) / 10;


Daarmee komt i sowieso op 15 uit, wat hetzelfde is als:

C:
1
2
3
int i = 10;

i = i * 1.5;


Het is iets van 5 instructies meer, maar volgens mij nog een stuk sneller :).
Je komt 150 uit en niet 15.

Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 15:47

CoolGamer

What is it? Dragons?

Er zit duidelijk een rekenfout in je formule. Die vermenigvuldiging van i met 10 is onjuist (je hebt immers het getal waarmee je gaat vermenigvuldigen al vermenigvuldigd met 10). Maar (zonder die *10 natuurlijk) kan je altijd een handige vermenigvuldiging maken.

[ Voor 25% gewijzigd door CoolGamer op 01-05-2011 22:04 ]

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

Verwijderd

keejoz schreef op zondag 01 mei 2011 @ 21:57:
[...]


Je komt 150 uit en niet 15.
Typefoutje :). Het had dit moeten zijn:

C:
1
2
3
int i = 10;

i = (i * 15) / 10;


Moeten zijn. Wat TheCoolGamer zei inderdaad :).

[ Voor 7% gewijzigd door Verwijderd op 01-05-2011 23:20 ]


Acties:
  • 0 Henk 'm!

  • Patriot
  • Registratie: December 2004
  • Laatst online: 16-09 13:49

Patriot

Fulltime #whatpulsert

((Heb jij ook altijd dat je per ongeluk delen van een formule mistypt) * 35)?

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 17:02
Als ik de spec hier pagina bekijk zou die uP zonder meer float berekeningen moeten kunnen.

Mis je een of ander vinkje in je linker configuratie?

[ Voor 3% gewijzigd door farlane op 02-05-2011 09:27 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

Verwijderd

Patriot schreef op maandag 02 mei 2011 @ 03:56:
[...]


((Heb jij ook altijd dat je per ongeluk delen van een formule mistypt) * 35)?
:+ het is duidelijk wat ik bedoel.

Acties:
  • 0 Henk 'm!

  • Reptile209
  • Registratie: Juni 2001
  • Laatst online: 13:19

Reptile209

- gers -

Verwijderd schreef op zondag 01 mei 2011 @ 23:18:
[...]


Typefoutje :). Het had dit moeten zijn:

C:
1
2
3
int i = 10;

i = (i * 15) / 10;


Moeten zijn. Wat TheCoolGamer zei inderdaad :).
Afhankelijk van de range van i kom je daar niet altijd mee weg. Als (bijvoorbeeld) je max_int = 32768, dan kom je dus in de problemen bij i > 2185. Vermenigvuldigen van i met 15 levert je dan een overflow op (of nog erger: onjuiste resultaten :X ).

Zo scherp als een voetbal!


Acties:
  • 0 Henk 'm!

  • Bolukan
  • Registratie: Oktober 2002
  • Laatst online: 23-08 23:43
Dit vergroot de range
C:
1
2
3
int i = 10;

i = (i * 3) / 2;


dit levert een nog grotere range, maar ook onnauwkeurigheid:
C:
1
2
3
int i = 10;

i = (i / 2) * 3;

Acties:
  • 0 Henk 'm!

Verwijderd

Reptile209 schreef op maandag 02 mei 2011 @ 14:44:
[...]

Afhankelijk van de range van i kom je daar niet altijd mee weg. Als (bijvoorbeeld) je max_int = 32768, dan kom je dus in de problemen bij i > 2185. Vermenigvuldigen van i met 15 levert je dan een overflow op (of nog erger: onjuiste resultaten :X ).
Dan gebruik je een unsigned int! :D

Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Bolukan schreef op maandag 02 mei 2011 @ 15:41:
Dit vergroot de range
C:
1
2
3
int i = 10;

i = (i * 3) / 2;


dit levert een nog grotere range, maar ook onnauwkeurigheid:
C:
1
2
3
int i = 10;

i = (i / 2) * 3;
In de eerste post stond het perfecte antwoord op deze vraag. Geen problemen met floating point, geen gebruik van een integer division unit die wellicht niet aanwezig is en de minste range problemen.


code:
1
i = i + (i >> 1)


Blijkbaar heeft het ding ook geen shift instructies dus word het waarschijnlijk een right-rotate, and en add en is daarmee waarschijnlijk ook de goedkoopste manier om dit te doen.

[ Voor 14% gewijzigd door PrisonerOfPain op 02-05-2011 16:03 ]


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 17:02
PrisonerOfPain schreef op maandag 02 mei 2011 @ 15:52:
In de eerste post stond het perfecte antwoord op deze vraag. Geen problemen met floating point, geen gebruik van een integer division unit die wellicht niet aanwezig is en de minste range problemen.
Een uP op 48MHz en met 2k RAM moet echt wel wat floating point math aankunnen. Nu ken ik die PICS ziet zo goed, maar ik neem toch aan dat er een C lib bij te krijgen moet zijn die die functies aan board heeft.

Zo niet, kijk eens naar een andere uP.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
farlane schreef op maandag 02 mei 2011 @ 17:07:
[...]

Een uP op 48MHz en met 2k RAM moet echt wel wat floating point math aankunnen. Nu ken ik die PICS ziet zo goed, maar ik neem toch aan dat er een C lib bij te krijgen moet zijn die die functies aan board heeft.

Zo niet, kijk eens naar een andere uP.
De informatie die ik postte kwam uit deze (de bovenste) datasheet. Als je floats wilt gaan emuleren met een C library, prima, maar mijn voorkeur heeft het niet.

Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

PrisonerOfPain schreef op maandag 02 mei 2011 @ 17:23:
[...]


De informatie die ik postte kwam uit deze (de bovenste) datasheet. Als je floats wilt gaan emuleren met een C library, prima, maar mijn voorkeur heeft het niet.
Waarom niet? Wordt hier uitvoerig gedaan bij zelfs relatief high-end ARM devices. Veel daarvan hebben ook geen FPU.

Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
EddoH schreef op maandag 02 mei 2011 @ 17:26:
[...]
Waarom niet? Wordt hier uitvoerig gedaan bij zelfs relatief high-end ARM devices. Veel daarvan hebben ook geen FPU.
Vooropgesteld, ik heb waarschijnlijk een iets andere achtergrond waarbij regelmatig het maximale uit de hardware gehaald moet worden en ik ben geen embedded developer in de 'klassieke' vorm. Kortom, de reden dat 't niet mijn voorkeur heeft is simpelweg omdat fixed-point waarschijnlijk een stuk beter presteerd en me betere afwegingen met betrekking tot de range & precision laat maken dan een floating point laag.

Op een moderne machine is het een ander verhaal, daar zorgen SIMD en een diepere floating point pipeline en dual issueing er voor dat floating point een heel stuk beter kan presteren; daarbij heb je in die gevallen meestal de beschikking over 32-bit registers en hoef je die niet ook te 'emuleren' (de aangehaalde PIC lijk 16-bit te zijn).

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 17:02
PrisonerOfPain schreef op maandag 02 mei 2011 @ 17:39:
Vooropgesteld, ik heb waarschijnlijk een iets andere achtergrond waarbij regelmatig het maximale uit de hardware gehaald moet worden en ik ben geen embedded developer in de 'klassieke' vorm. Kortom, de reden dat 't niet mijn voorkeur heeft is simpelweg omdat fixed-point waarschijnlijk een stuk beter presteerd en me betere afwegingen met betrekking tot de range & precision laat maken dan een floating point laag.
Als je gaat voor maximale performance is soft-float niet echt wenselijk, dat ben ik met je eens. De tijd echter dat dit soort uP's tot aan het laatste grammetje worden uitgekleed is echter ook voorbij. ( al lijkt Microchip op dat vlak wat achter te lopen lijkt het af en toe )

Dus ik zou zeggen gebruik gewoon floats als je die nodig hebt, tenzij blijkt dat je perfomance/ruimteproblemen krijgt. ( Eigenlijk is dit een variatie op het 'premature optimization' effect. )

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

PrisonerOfPain schreef op maandag 02 mei 2011 @ 17:39:
[...]


Vooropgesteld, ik heb waarschijnlijk een iets andere achtergrond waarbij regelmatig het maximale uit de hardware gehaald moet worden en ik ben geen embedded developer in de 'klassieke' vorm. Kortom, de reden dat 't niet mijn voorkeur heeft is simpelweg omdat fixed-point waarschijnlijk een stuk beter presteerd en me betere afwegingen met betrekking tot de range & precision laat maken dan een floating point laag.

Op een moderne machine is het een ander verhaal, daar zorgen SIMD en een diepere floating point pipeline en dual issueing er voor dat floating point een heel stuk beter kan presteren; daarbij heb je in die gevallen meestal de beschikking over 32-bit registers en hoef je die niet ook te 'emuleren' (de aangehaalde PIC lijk 16-bit te zijn).
Puur performance-technisch gezien is het inderdaad niet ideaal nee. Bij embedded devices is het kostenplaatje echter een een flinke factor, waarbij er dan vaak wordt bezuinigd op een FPU. met de nieuwe EABI van ARM is er echter een stuk beter met floating points te werken :)

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
neliss schreef op zondag 01 mei 2011 @ 20:52:
Goedenavond,

Ik ben bezig met het programmeren van een PIC microcontroller.
Nu zit ik met de situatie dat ik een integer zou willen vermenigvuldigen met 1.5 (wat dus een float is).
Zelf had ik gedacht dit te kunnen doen met:
code:
1
(int) (i * 1.5)

Maar helaas geeft dit niet het gewenste resultaat.
Ik kan niet goed zien wat er misgaat, omdat ik de waarde van het getal niet precies kan achterhalen omdat ik geen display heb voor het debuggen.
Ik kan alleen met ledjes het getal weergeven, maar deze blijven allemaal uit na de vermenigvuldiging (=0).
Wat wel goed gaat:
code:
1
2
3
(int) (i * 1)
of
(int) (i * 2)

Heeft iemand een idee wat er aan de hand kan zijn?
Die 1.5 is geen float trouwens dat is een double als je een float literal wil in C/C++ moet je de "f" suffix gebruiken, dus:
1.5 <= double
1.5f <= float

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max

Pagina: 1