rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Ik wilde testen of een float variabele (uit de flash-config) een beetje kon kloppen, zonee dan een default waarde toekennen:
if ((vcc > VCC_MAX) ||
(vcc < VCC_MIN))
vcc = 3.30;
Dit bleek niet te werken: De lege flash gaf een "nan" waarde en dan triggert geen van beide tests....
Wat is het idee? nan is NIET kleiner dan iedere waarde maar ook NIET groter dan iedere waarde?
Moet ik schrijven;
if (!((vcc < VCC_MAX) &&
(vcc > VCC_MIN)))
vcc = 3.30;
?
Ik heb nu een expliciete "isnan()" call staan.....
Ik vind de originele code het best "leesbaar", is er een nettere schrijfwijze dan de voorgestelde nieuwe code of mijn expliciete derde clausule?
[Bericht gewijzigd door rew op (11%)]
van StackOverflow:
However, the <math.h> comparison macros are required to follow NaN rules equivalent to IEEE 754's. The following from the C11 draft N1580 under 7.12.14 Comparison Macros states that the <math.h> comparison macros are required to ensure that, if either or both of x, y are NaNs then:
isunordered(x, y) is true
isgreater(x, y), isgreaterequal(x, y), isless(x, y), islessequal(x, y) are all false
Zelf zou ik hier denk ik expliciet testen op NAN om vast te leggen dat dat hier een mogelijkheid is die afgevangen moet worden. Bovendien heb ik nogal een aversie tegen negatieve logica
maar dat schijnt iets persoonlijks te zijn want het wordt erg veel gebruikt.
Hetzelfde probleem kan misschien ook optreden bij +/- INFINITY?
Waarom niet eerst een algemene test op een lege flash voordat je variabelen uit de flash gaat uitlezen en gebruiken?
SparkyGSX
Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken
Juist bij floating point is het belangrijk om te checken dat je een geldige waarde hebt gekregen, zeker als je die uit flash of via een communicatie interface hebt gekregen.
Ik zat me net af te vragen waarom ik dit in ~25 jaar programmeren nooit bij de hand heb gehad, maar dat is vrij simpel: ik vermijd floating point als de pest in microcontrollers, en al helemaal als die uit een mogelijk onbetrouwbare bron komen.
Als je gewoon een range check doet, x>=min && x<=max vang je de NaN automatisch.
Fouten in de data-overdracht in een communicatie kanaal (flash o.i.d.) detecteer je met fout-detectie methodieken zoals CRC, het alleen controleren van onbekende floatingpoint of integer getallen of andere onbekende data in dat communicatie kanaal is zinloos.
ik vermijdt floating point als de pest in microcontrollers
Dat idee had ik ook altijd vroeger. Maar ik ben inmiddels helemaal om. Qua performance is het vaak beter dan integers met scaling, en alles wordt zo veel gemakkelijker.
daar sluit ik me ook bij aan. "Vroegah" in de 8 bitters, was het vaak ook ene no go, deden we alles fixed point. Maar dan kreeg je soms zulke onleesbare formules omdat alles gescaled moest worden met x1000 en / 100000 etc. inclusief alle afrondingsfouten die daarbij optraden.
Nu op de arms die vaak ook flash en ram in overvloed hebben als mede cpu power prefereer ik waar nodig het gebruik van floats als ik daarmee gewoon een formule kan schrijven zoals hij bedoeld is.
Wel aan wat standaard float regels houden uiteraard
hardbass
PE2BAS
Ik zou zelf voor zoiets gaan. Als je C++ gebruikt zou je ClampFloat ook clamp kunnen noemen. Dan kan je overloading gebruiken om ook andere types te implementeren.
Ik heb even voor het voorbeeld nog een paar checks toegevoegd. Geen idee of je die wilt, maar dan weet je dat ze bestaan. Uiteraard zijn positive en negative infinity al overbodig vanwegen de min, max checks.
float ClampFloat(float value, const float min, const float max)
{
// Check for NaN and set to 0 if true
if (std::isnan(value))
{
return 0.0f;
}
// Check for positive infinity
if (std::isinf(value) && value > 0)
{
return VCC_MAX;
}
// Check for negative infinity
if (std::isinf(value) && value < 0)
{
return VCC_MIN;
}
// Check for underflow and set to 0 if true
if (std::fpclassify(value) == FP_SUBNORMAL)
{
return 0.0f;
}
// Ensure that the value is within the specified range
if (value > max)
{
value = max;
}
else if (value < min)
{
value = min;
}
// Return the clamped value
return value;
}
void LoadSettings()
{
float vcc = ClampFloat(settings.vcc, VCC_MIN, VCC_MAX);
}
[Bericht gewijzigd door hardbass op (31%)]
Op 3 december 2023 17:31:01 schreef rew:
Ik vind de originele code het best "leesbaar", is er een nettere schrijfwijze dan de voorgestelde nieuwe code of mijn expliciete derde clausule?
//Choices: isnan() does not trigger on infinity, isinf() not on NaN
// but isnormal() fails on zero. Used isnormal() as 0 is not a practical
// supply voltage.
#define IS_VALID_VCC(v) ( isnormal(v) && \ // Valid float
(v < VCC_MAX) && \ // between max
(v > VCC_MIN) ) // and min
if (! IS_VALID_VCC(vcc)) {
vcc = 3.3
}
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Op 3 december 2023 20:30:43 schreef SparkyGSX:
Als je gewoon een range check doet, x>=min && x<=max vang je de NaN automatisch.
Wat mij betreft, en ook voor de "int" variabelen, is de logica: Als ie kleiner dan MIN is, moet ie op de default waarde gezet worden. Als ie groter dan MAX is, moet ie op de default waarde gezet worden.
Dat kan je dan ook nog schrijven als: if kleiner dan min OF groter dan max zet op default.
Wat jij voorstelt dat is if in_range then ... nothing else zet op default. Ik wilde de lege IF clausule vermijden. En dan krijg je de kleiner dan MIN OF groter dan MAX. En die werkte dus niet.
In de "runt 40000x per seconde" code heb ik wat brainpower zitten spenderen om het allemaal met ints te doen. Toen "voorlopig" even in floats geschreven en dat werkte en haalde gewoon makkelijk de "deadline" van 25 microseconden. En toen was het: Waarom eigenlijk moeilijk doen.
Het kan 100% zeker gewoon helemaal in INT geprogrammeerd worden. Het "floating" gedeelte van "floating point" heb ik eigenlijk nergens nodig. Dus met een geschikte schaling van de interpretatie van de ints gaat het ook gewoon lukken.
Op 4 december 2023 01:14:07 schreef deKees:
Dat idee had ik ook altijd vroeger. Maar ik ben inmiddels helemaal om.
Idem! Dat het echt sneller is betwijfel ik maar goed. In bepaalde gevallen zal het wel eens zo kunnen zijn als je extra schaal-factoren nodig hebt om je tussenresultaten "binnen range" te houden. Het hangt er een beetje van af hoe groot deel van je 32 bits je gebruikt. Als je 24bits nauwkeurigheid nodig hebt, kan je tussenresultaten niet meer dan 256 keer groter laten worden dan 1 van de variabelen. Dus een vermenigvuldiging van 2 van die waardes moet al in een 64-bit gaan gebeuren en dan kan je wel eens verliezen van de FP unit die zo'n vermenigvuldiging in 1 cycle kan. (Maar STM32F0 en RP2040 (die ik veel gebruik) hebben geen FP unit).
Op 4 december 2023 08:27:47 schreef hardbass:
Ik zou zelf voor zoiets gaan. Als je C++ gebruikt zou je ClampFloat ook clamp kunnen noemen.
Ik maak een "copie van flash in RAM" waar ik, evt met userinterface, wijzigingen in kan aanbrengen. En dan kan je kiezen of de "huidige configuratie" werkt/handig is en wegschrijven of niet. In het onderhavige project doen we dat bijvoorbeeld (soms) bij het testen. (niet wegschrijven: de default instelling is zoals de klant het wil hebben).
Maar omdat ik niet zeker weet of "+INF" ook als NAN gezien gaat worden, ga ik dan toch maar de "lege if" constructie schrijven.
hardbass
PE2BAS
@Blurp als je het zo oplost, zou ik het generieker maken zodat hij voor meer is toe te passen:
#define IS_WITHIN_RANGE(v, min, max) ( isnormal(v) && \ // Valid float
(v < max) && \ // between max
(v > min) ) // and min
if (! IS_WITHIN_RANGE(vcc, VCC_MIN, VCC_MAX)) {
vcc = 3.3
}
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Ik had de nan test er nog in zitten. Toen kwam ik een ander probleem tegen wat gisteren nog ondenkbaar was.
Na het programmeren van de printjes boot de CPU en die heeft dan in milliseconden door als er kortsluitingen op de pinnen zitten. Als ik dat op een bekende plek in het geheugen zet, dan kan ik dat daar vrijwel direct na het programmeren teruglezen en aan degene achter de programmeer-computer rapporteren!
Ik heb daar ook de gemeten VCC tussen staan. Het teruglezen van de float tussen ARM en x86 PC lukte even niet. De ints gingen wel goed. Ik heb nu dus gewoon de VCC maar een Int gemaakt in millivolts. Klaar. Bij het uitlezen van de flash wordt config.myvcc/1000 dan in een float vcc variabele gezet. Lost ook het originele probleem van deze thread op.
Update: Het werkt nu! Eentje die eerder als "kortsluiting bij het display" gemarkeerd was, die werd nu als "kortsluiting tussen pootje 18 en 19" door het programmeer scriptje herkend, en na het hersolderen van pootje 18 en 19 (en een paar pins d'r om heen) komt ie nu wel door de test!
[Bericht gewijzigd door rew op (16%)]