|
| Underligt eller er det bare mig der gør de~ Fra : Morten Larsen |
Dato : 27-08-05 11:44 |
|
Jeg har følgende kode:
unsigned long addr;
int a,b,c,d;
a = 192;
b = 168;
c = 1;
d = 1;
addr = ( (a * pow(256,3)) + (b * pow(256,2)) + (c * pow(256,1)) + (d
* pow(256,0)) );
Hvis jeg åbner borland c++ builder, og indsætter ovenstående kode i en form
får addr det ønskede resultat.
Men indsætter jeg koden i et C program (ikke c++), får addr et forkert
resultat. dvs. at udregningerne bliver forkerte. Mit problem er så at denne
formel skal regnes i et C program og det er ikke en mulighed for at gører
dette i c++, da programmet skal være i C.
Håber nogen har en ide om hvad der går galt?
//Morten
| |
Mogens Hansen (27-08-2005)
| Kommentar Fra : Mogens Hansen |
Dato : 27-08-05 12:16 |
|
"Morten Larsen" <not@4u.com> wrote in message
news:431043fa$0$37101$edfadb0f@dread12.news.tele.dk...
[8<8<8<]
> Mit problem er så at denne formel skal regnes i et C program og det er
> ikke en mulighed for at gører dette i c++, da programmet skal være i C.
Hvis du oversætter det med C++Builder som C går det også fint.
Der er den forskel på C og C++ programmet at i C findes der kun een "pow"
funktion:
double pow(double, double);
I C++ er der en række overloads:
float pow (float, float);
float pow (float, int);
double pow(double, int);
long double pow (long double, long double);
long double pow (long double, int);
template<class T> complex<T> pow(const complex<T>&, int);
template<class T> complex<T> pow(const complex<T>&, const T&);
template<class T> complex<T> pow(const complex<T>&, const complex<T>&);
template<class T> complex<T> pow(const T&, const complex<T>&);
template<class T> valarray<T> pow(const T&, const valarray<T>&);
template<class T> valarray<T> pow(const valarray<T>&, const valarray<T>&);
template<class T> valarray<T> pow (const valarray<T>&, const T&);
template<class T> valarray<T> pow (const T&, const valarray<T>&);
Det er den 2. eller 3. der bliver brugt i dit program.
>
> Håber nogen har en ide om hvad der går galt?
Hvor stor er en unsigned long på den anden platform ?
Hvorfor bruger du egentlig en runtime beregning, når det egentlig er compile
time konstanter og du går endda over floating point beregning.
Et alternativ er
addr = a*16777216 + b*65536 + c*256 +d;
eller måske endnu tydeligere
addr = (((unsigned long) a) << 24) +
(((unsigned long) b) << 16) +
(((unsigned long) c) << 8) +
(((unsigned long) d) << 0);
Det er langt tydeligere hvad det laver og det kører formodentlig også
hurtigere.
Venlig hilsen
Mogens Hansen
| |
Morten Larsen (27-08-2005)
| Kommentar Fra : Morten Larsen |
Dato : 27-08-05 12:53 |
|
"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:43104b8e$0$78284$157c6196@dreader1.cybercity.dk...
>
> "Morten Larsen" <not@4u.com> wrote in message
> news:431043fa$0$37101$edfadb0f@dread12.news.tele.dk...
>
> [8<8<8<]
>> Mit problem er så at denne formel skal regnes i et C program og det er
>> ikke en mulighed for at gører dette i c++, da programmet skal være i C.
>
> Hvis du oversætter det med C++Builder som C går det også fint.
>
> Der er den forskel på C og C++ programmet at i C findes der kun een "pow"
> funktion:
> double pow(double, double);
> I C++ er der en række overloads:
> float pow (float, float);
> float pow (float, int);
> double pow(double, int);
> long double pow (long double, long double);
> long double pow (long double, int);
> template<class T> complex<T> pow(const complex<T>&, int);
> template<class T> complex<T> pow(const complex<T>&, const T&);
> template<class T> complex<T> pow(const complex<T>&, const complex<T>&);
> template<class T> complex<T> pow(const T&, const complex<T>&);
> template<class T> valarray<T> pow(const T&, const valarray<T>&);
> template<class T> valarray<T> pow(const valarray<T>&, const
> valarray<T>&);
> template<class T> valarray<T> pow (const valarray<T>&, const T&);
> template<class T> valarray<T> pow (const T&, const valarray<T>&);
>
> Det er den 2. eller 3. der bliver brugt i dit program.
>
>>
>> Håber nogen har en ide om hvad der går galt?
>
> Hvor stor er en unsigned long på den anden platform ?
>
> Hvorfor bruger du egentlig en runtime beregning, når det egentlig er
> compile time konstanter og du går endda over floating point beregning.
> Et alternativ er
> addr = a*16777216 + b*65536 + c*256 +d;
> eller måske endnu tydeligere
> addr = (((unsigned long) a) << 24) +
> (((unsigned long) b) << 16) +
> (((unsigned long) c) << 8) +
> (((unsigned long) d) << 0);
>
> Det er langt tydeligere hvad det laver og det kører formodentlig også
> hurtigere.
Du har helt ret i ovenstående undtagen at det dog er den rigtige pow der
bruges
Jeg har prøvet en del i C, for at få det til at virke.
Men problemet er ikke i pow, tror snare det er * (gange) der driller.
Min udregning: -1062731519
Din nummer 1: -1062731519
Dim nummer 2: -1062731519
Men resultatet i cpp og andre sprog jeg har testet i, bliver resultatet
ikke -1062731519 men 32322355777.
Jeg vil gerne have det samme resultat i C :) Så håber du kan hjælpe mig med
det?
Jeg vil formentlig også lide under dette problem når jeg konvertere tilbage.
a = floor( addr / pow(256,3) );
b = floor( (addr % (int)pow(256,3)) / pow(256,2) );
c = floor( ( (addr % (int)pow(256,3)) % (int)pow(256,2) ) /
pow(256,1) );
d = floor( ( ( (addr % (int)pow(256,3)) % (int)pow(256,2) ) %
(int)pow(256,1) ) / pow(256,0) );
Ovenstående har du sikkert også en nemmere og bedre måde at gøre på?
//Morten
| |
Kent Friis (27-08-2005)
| Kommentar Fra : Kent Friis |
Dato : 27-08-05 13:02 |
|
Den Sat, 27 Aug 2005 13:53:24 +0200 skrev Morten Larsen:
>
> Jeg har prøvet en del i C, for at få det til at virke.
> Men problemet er ikke i pow, tror snare det er * (gange) der driller.
>
> Min udregning: -1062731519
> Din nummer 1: -1062731519
> Dim nummer 2: -1062731519
>
> Men resultatet i cpp og andre sprog jeg har testet i, bliver resultatet
> ikke -1062731519 men 32322355777.
>
> Jeg vil gerne have det samme resultat i C :) Så håber du kan hjælpe mig med
> det?
Det svarede han faktisk også på, hvis du læser *hele* svaret.
> Jeg vil formentlig også lide under dette problem når jeg konvertere tilbage.
>
> a = floor( addr / pow(256,3) );
> b = floor( (addr % (int)pow(256,3)) / pow(256,2) );
> c = floor( ( (addr % (int)pow(256,3)) % (int)pow(256,2) ) /
> pow(256,1) );
> d = floor( ( ( (addr % (int)pow(256,3)) % (int)pow(256,2) ) %
> (int)pow(256,1) ) / pow(256,0) );
>
> Ovenstående har du sikkert også en nemmere og bedre måde at gøre på?
and (&), shift right (>>).
Skal vi gætte på du er matematiker og ikke programmør? Den måde du
gør det på er matematisk korrekt, det der bare ikke den en programmør
ville vælge, da bit-operationerne (shift left/right, and, or, xor, not)
er beregnet specifikt til formålet, og nemmere for både mennesker og
computere at forstå.
Mvh
Kent
--
Hard work may pay off in the long run, but laziness pays off right now.
| |
Morten Larsen (27-08-2005)
| Kommentar Fra : Morten Larsen |
Dato : 27-08-05 13:36 |
|
"Kent Friis" <nospam@nospam.invalid> skrev i en meddelelse
news:43105620$0$18650$14726298@news.sunsite.dk...
> Den Sat, 27 Aug 2005 13:53:24 +0200 skrev Morten Larsen:
>> Jeg vil gerne have det samme resultat i C :) Så håber du kan hjælpe mig
>> med
>> det?
>
> Det svarede han faktisk også på, hvis du læser *hele* svaret.
I må meget undskylde, men så kan jeg altså ikke se det :)
Mogens gav 2 andre eksempler på hvordan det kan gøres.
Jeg prøvede dem, men resultatet er stadig det samme.
Det jeg ikke forstår er hvorfor addr bliver lig med "-1062731519" i C.
Når de samme udregninger (min måde, og mogens' 2 måder) i C++ bliver lig med
"32322355777"
>> Jeg vil formentlig også lide under dette problem når jeg konvertere
>> tilbage.
>>
>> a = floor( addr / pow(256,3) );
>> b = floor( (addr % (int)pow(256,3)) / pow(256,2) );
>> c = floor( ( (addr % (int)pow(256,3)) % (int)pow(256,2) ) /
>> pow(256,1) );
>> d = floor( ( ( (addr % (int)pow(256,3)) % (int)pow(256,2) ) %
>> (int)pow(256,1) ) / pow(256,0) );
>>
>> Ovenstående har du sikkert også en nemmere og bedre måde at gøre på?
>
> and (&), shift right (>>).
Mange tak, men ville ønske jeg vidste hvordan jeg skulle bruge dem :)
> Skal vi gætte på du er matematiker og ikke programmør? Den måde du
> gør det på er matematisk korrekt, det der bare ikke den en programmør
> ville vælge, da bit-operationerne (shift left/right, and, or, xor, not)
> er beregnet specifikt til formålet, og nemmere for både mennesker og
> computere at forstå.
Jeg vil hverken kalde mig for matematiker eller pro programmør :)
Jeg sad med problemet at skulle arbejde med ip ranges.
Efter søgning på google fandt jeg den formel jeg brugte i mit første indlæg.
Men kan fornemme at jeg skal lære lidt bit-operationer :)
//Morten
| |
Mogens Hansen (27-08-2005)
| Kommentar Fra : Mogens Hansen |
Dato : 27-08-05 13:46 |
|
"Morten Larsen" <not@4u.com> wrote in message
news:43105e38$0$25947$edfadb0f@dread12.news.tele.dk...
>
> "Kent Friis" <nospam@nospam.invalid> skrev i en meddelelse
> news:43105620$0$18650$14726298@news.sunsite.dk...
>> Den Sat, 27 Aug 2005 13:53:24 +0200 skrev Morten Larsen:
>
>>> Jeg vil gerne have det samme resultat i C :) Så håber du kan hjælpe mig
>>> med
>>> det?
>>
>> Det svarede han faktisk også på, hvis du læser *hele* svaret.
>
> I må meget undskylde, men så kan jeg altså ikke se det :)
Jeg skrev:
"Hvis du oversætter det med C++Builder som C går det også fint."
Venlig hilsen
Mogens Hansen
| |
Michael Rasmussen (27-08-2005)
| Kommentar Fra : Michael Rasmussen |
Dato : 27-08-05 13:53 |
|
On Sat, 27 Aug 2005 14:36:18 +0200, Morten Larsen wrote:
> Jeg vil hverken kalde mig for matematiker eller pro programmør :) Jeg
> sad med problemet at skulle arbejde med ip ranges. Efter søgning på
> google fandt jeg den formel jeg brugte i mit første indlæg. Men kan
> fornemme at jeg skal lære lidt bit-operationer :)
>
Du gør den fejl, at du tænker talrækken ud fra grundtallet 10.
Computeren regner ud fra grundtallet 2.
<< betyder faktisk at dividere med 2, mens >> betyder at gange med 2. Det
svarer til når du flytter decimalpunktum til venstre eller højre i
ti-tals systemet; flyt til venstre <=> dividere med grundtallet, og
flyt til højre <=> gange med grundtallet.
Det smarte ved en computer er så, at shift-operationen kun kræver en
instruktion, mens gange og dividere kræver flere operationer - afhænger
af tallets størrelse, og hvor mange bit din CPU kan håndterer per
operation.
--
Hilsen/Regards
Michael Rasmussen
http://keyserver.veridis.com:11371/pks/lookup?op=get&search=0xE3E80917
| |
Kent Friis (27-08-2005)
| Kommentar Fra : Kent Friis |
Dato : 27-08-05 14:39 |
|
Den Sat, 27 Aug 2005 14:36:18 +0200 skrev Morten Larsen:
>
> "Kent Friis" <nospam@nospam.invalid> skrev i en meddelelse
> news:43105620$0$18650$14726298@news.sunsite.dk...
>> Den Sat, 27 Aug 2005 13:53:24 +0200 skrev Morten Larsen:
>
>>> Jeg vil gerne have det samme resultat i C :) Så håber du kan hjælpe mig
>>> med
>>> det?
>>
>> Det svarede han faktisk også på, hvis du læser *hele* svaret.
>
> I må meget undskylde, men så kan jeg altså ikke se det :)
Det var heller ikke så stort
> Mogens gav 2 andre eksempler på hvordan det kan gøres.
Og midt imellem stod denne linie:
>>>>Hvor stor er en unsigned long på den anden platform ?
Det er lige præcis det der er problemet. Hvis den er 32 bits, kan
en signed kun indeholde 31 bits plus fortegnet, og en unsigned kan
indeholde alle 32 bits.
Når man så propper 32 bits ind i en signed long der kun kan indeholde
31, så ryger den sidste op og overskriver fortegnet. Bang, negative
tal.
Prøv at lave alle fem variable unsigned long, og se om ikke det løser
problemet, uanset hvilken metode du bruger.
>>> a = floor( addr / pow(256,3) );
>>> b = floor( (addr % (int)pow(256,3)) / pow(256,2) );
>>> c = floor( ( (addr % (int)pow(256,3)) % (int)pow(256,2) ) /
>>> pow(256,1) );
>>> d = floor( ( ( (addr % (int)pow(256,3)) % (int)pow(256,2) ) %
>>> (int)pow(256,1) ) / pow(256,0) );
>>>
>>> Ovenstående har du sikkert også en nemmere og bedre måde at gøre på?
>>
>> and (&), shift right (>>).
>
> Mange tak, men ville ønske jeg vidste hvordan jeg skulle bruge dem :)
a=addr>>24;
b=(addr>>16) & 255;
c=(addr>>8) & 255;
d=addr & 255;
> Jeg vil hverken kalde mig for matematiker eller pro programmør :)
> Jeg sad med problemet at skulle arbejde med ip ranges.
> Efter søgning på google fandt jeg den formel jeg brugte i mit første indlæg.
Bad luck. Den der har skrevet formlen må være matematiker og ikke
programmør
> Men kan fornemme at jeg skal lære lidt bit-operationer :)
Det gør den slags *meget* nemmere (og hurtigere, medmindre compileren
kan se "hov, han dividere med 263^3, det der det samme som >>24).
Mvh
Kent
--
Hard work may pay off in the long run, but laziness pays off right now.
| |
Mogens Hansen (27-08-2005)
| Kommentar Fra : Mogens Hansen |
Dato : 27-08-05 15:19 |
|
"Morten Larsen" <not@4u.com> wrote in message
news:43105e38$0$25947$edfadb0f@dread12.news.tele.dk...
[8<8<8<]
> Det jeg ikke forstår er hvorfor addr bliver lig med "-1062731519" i C.
Hvordan ser du at den har den værdi ?
Lidt mere præcist:
Du har i det program angivet at "addr" er af typen "unsigned long".
Hvordan kan en "unsigned" antage en negativ værdi ?
Bruger du f.eks. printf (i en eller anden variant) med forkert format
specifier eller en debugger der fejlfortolker "unsigned long"`?
Venlig hilsen
Mogens Hanen
| |
Morten Larsen (27-08-2005)
| Kommentar Fra : Morten Larsen |
Dato : 27-08-05 16:03 |
|
"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:43107669$0$78284$157c6196@dreader1.cybercity.dk...
>
> "Morten Larsen" <not@4u.com> wrote in message
> news:43105e38$0$25947$edfadb0f@dread12.news.tele.dk...
>
> [8<8<8<]
>> Det jeg ikke forstår er hvorfor addr bliver lig med "-1062731519" i C.
>
> Hvordan ser du at den har den værdi ?
Se længere nede
> Lidt mere præcist:
> Du har i det program angivet at "addr" er af typen "unsigned long".
> Hvordan kan en "unsigned" antage en negativ værdi ?
Ja det aner jeg heller ikke, derfor jeg spørger her :)
Som jeg har forstået det:
unsigned = kun positive numre.
signed = positive og negative numre
Og udfra hvad Kent skrev, tolker jeg det sådan at unsigned kan holde en
større positiv værdi end signed da den første bit ikke skal bruges til at
indikere om tallet er positivt eller negativt.
Er det rigtigt forstået?
> Bruger du f.eks. printf (i en eller anden variant) med forkert format
> specifier eller en debugger der fejlfortolker "unsigned long"`?
Ja, i C testen bruger jeg printf("Resultat: %d", addr);
Og i min cpp test bruger jeg Form1->Caption ) (AnsiString)addr;
Jeg har lige været over og handle, på den tur tænkte jeg faktisk på at det
kunne være printf.
Jeg har lige ændret printf("Resultat: %d", addr) til
_i64toa(addr, str, 10);
printf(str);
Og nu virker det. Så forstår jeg meget bedre det har givet mig så mange
problemer.
Det andet gav nemlig ingen mening. Og vidste ikke dette var et problem med
printf.
Men i skal alle sammen have mange tak for hjælpen :)
//Morten
| |
Mogens Hansen (27-08-2005)
| Kommentar Fra : Mogens Hansen |
Dato : 27-08-05 16:14 |
|
"Morten Larsen" <not@4u.com> wrote in message
news:431080a3$0$37076$edfadb0f@dread12.news.tele.dk...
>
> "Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
[8<8<8<]
>> Bruger du f.eks. printf (i en eller anden variant) med forkert format
>> specifier eller en debugger der fejlfortolker "unsigned long"`?
>
> Ja, i C testen bruger jeg printf("Resultat: %d", addr);
Det var hvad jeg forestillede mig.
Hvad betyder "%d": signed decimal integer
printf familien er _ikke_ typesikker (det har gennem tiderne givet masser af
problemer). Den fortolker bitmønsteret på stakken i henhold til
formatstrengen - uanset hvad der måtte ligge der.
Det vil sige at når du skriver signed integer, så bliver det tolket som
sådan, og som Arne Valhøj skrev så har -1062731519L og 3232235777UL er samme
bit mønster.
Du skal skrive "%ul" i stedet når "addr" har typen "unsigned long".
Venlig hilsen
Mogens Hansen
| |
Arne Vajhøj (27-08-2005)
| Kommentar Fra : Arne Vajhøj |
Dato : 27-08-05 16:16 |
|
Morten Larsen wrote:
> Ja, i C testen bruger jeg printf("Resultat: %d", addr);
> Og i min cpp test bruger jeg Form1->Caption ) (AnsiString)addr;
> Jeg har lige været over og handle, på den tur tænkte jeg faktisk på at det
> kunne være printf.
>
> Jeg har lige ændret printf("Resultat: %d", addr) til
> _i64toa(addr, str, 10);
> printf(str);
>
> Og nu virker det. Så forstår jeg meget bedre det har givet mig så mange
> problemer.
> Det andet gav nemlig ingen mening. Og vidste ikke dette var et problem med
> printf.
printf bør virke hvis du erstatter %d med %lu
Arne
| |
Mogens Hansen (27-08-2005)
| Kommentar Fra : Mogens Hansen |
Dato : 27-08-05 13:30 |
|
"Morten Larsen" <not@4u.com> wrote in message
news:4310542a$0$37092$edfadb0f@dread12.news.tele.dk...
[8<8<8<]
> Men problemet er ikke i pow, tror snare det er * (gange) der driller.
Nej det er et "signed"/"unsigned" + overflow problem.
Programmet
int main()
{
unsigned long addr;
int a,b,c,d;
a = 192;
b = 168;
c = 1;
d = 1;
addr = (((unsigned) a) << 24) +
(((unsigned) b) << 16) +
(((unsigned) c) << 8) +
(((unsigned) d) << 0);
return 0;
}
vil give det rigtige på alle (fungerende) platforme hvis "unsigned long"
minimum er 32 bit.
>
> Min udregning: -1062731519
> Din nummer 1: -1062731519
> Dim nummer 2: -1062731519
Nej.
Som jeg skrev så giver de det rigtige resultat, når der er oversat som et C
program med C++Builder - jeg havde prøvet.
Oversætter du til en anden platform ?
>
> Men resultatet i cpp og andre sprog jeg har testet i, bliver resultatet
> ikke -1062731519 men 32322355777.
Prøv at lægge 1062731519 og 3232235777 sammen, så vil du se at det er 2^32.
Det er et vink med en vognstang.
Hvis du prøver at gemme resultatet i en 32 bit _signed_ integer så får du
netop det negative resultat.
> Jeg vil gerne have det samme resultat i C :) Så håber du kan hjælpe mig
> med det?
Det har, som jeg skrev, ikke noget med C vs. C++ at gøre.
[8<8<8<]
> Ovenstående har du sikkert også en nemmere og bedre måde at gøre på?
Ja - det har jeg allerede beskrevet.
Venlig hilsen
Mogens Hansen
| |
Troels Thomsen (30-08-2005)
| Kommentar Fra : Troels Thomsen |
Dato : 30-08-05 08:36 |
|
> unsigned long addr;
> int a,b,c,d;
> a = 192;
> b = 168;
> c = 1;
> d = 1;
> addr = (((unsigned) a) << 24) +
> (((unsigned) b) << 16) +
> (((unsigned) c) << 8) +
> (((unsigned) d) << 0);
> return 0;
> }
>
> vil give det rigtige på alle (fungerende) platforme hvis "unsigned long"
> minimum er 32 bit.
>
Er der ikke også et krav til int'erne ?
Har en char, skiftet op med 24, ikke udefineret værdi?
tpt
| |
Mogens Hansen (30-08-2005)
| Kommentar Fra : Mogens Hansen |
Dato : 30-08-05 09:39 |
|
"Troels Thomsen" <asdf@asdf.dk> wrote in message
news:43140c53$0$2312$edfadb0f@dread11.news.tele.dk...
[8<8<8<]
> Er der ikke også et krav til int'erne ?
Jo, de skal også være minimum 32 bit.
Det var sikkert bedre hvis a,b,c, og d var castet til "unsigned long",
> Har en char, skiftet op med 24, ikke udefineret værdi?
Typen af resultatet af en "char" skiftet 24 bit er "int" eller "unsigned
int" ud fra reglerne om "integral promotion".
Hvis "int" eller "unsigned int" er mindre end 32 bit giver det en udefineret
værdi.
Venlig hilsen
Mogens Hansen
| |
Arne Vajhøj (27-08-2005)
| Kommentar Fra : Arne Vajhøj |
Dato : 27-08-05 13:39 |
|
Morten Larsen wrote:
> Jeg har prøvet en del i C, for at få det til at virke.
> Men problemet er ikke i pow, tror snare det er * (gange) der driller.
>
> Min udregning: -1062731519
> Din nummer 1: -1062731519
> Dim nummer 2: -1062731519
>
> Men resultatet i cpp og andre sprog jeg har testet i, bliver resultatet
> ikke -1062731519 men 32322355777.
> Jeg vil gerne have det samme resultat i C :) Så håber du kan hjælpe mig med
> det?
Du har samme resultat i C !
Du har bare glemt unsigned keyworded.
-1062731519L og 3232235777UL er samme bit mønster.
Arne
| |
|
|