CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PIC24EP unsigned int64 calculations [SOLVED]
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PIC24EP unsigned int64 calculations [SOLVED]
PostPosted: Wed Oct 14, 2020 2:02 pm     Reply with quote

Compiler: 5.026
Device: PIC24EP512GP806

Hi again,

To make a long story short, I am trying to do a calculation using unsigned int64 values. The result is plain wrong and I'm going nuts. The values indicated below come from an SD card driver. I use certain values to calculate the card size and the amount of space left when my MCU boots.

Important note: This exact same code returns the expected numbers using a 2GB and a 4GB SD card. The problem is with a 32GB SD card. I don't have an 8 nor a 16 to test.

unsigned int64 Val1 = 32768;
unsigned int64 Val2 = 976991;
unsigned int64 Val3 = Val1 * Val2;

Do this on a calculator --> 32768 * 976991 = 32,014,041,088 <----- This is the correct answer.

But this same calculation on the MCU returns 1,949,270,016.

So here's the original source code followed by the output on the screen:

Screen printed values returned by the SD card driver:
fs->fs_type = 3
fs->sects_clust = 64
fs->sects_fat = 7633
fs->max_clust = 976994

Code:
unsigned int64 Val1 = 512 * fs->sects_clust;
unsigned int64 Val2 = fs->max_clust - fs->fs_type;
unsigned int64 Val3 = Val1 * Val2;

fprintf( MONITOR_SERIAL, "\n\r\n\r1) Val1 = 512 * fs->sects_clust ------------> 512 * %d = %Lu", fs->sects_clust, 512 * fs->sects_clust );
fprintf( MONITOR_SERIAL, "\n\r2) Val2 = fs->max_clust - fs->fs_type -----> %Ld - %d = %Lu", fs->max_clust, fs->fs_type, fs->max_clust - fs->fs_type );
fprintf( MONITOR_SERIAL, "\n\r3) Val3 = Val1 * Val2 ------------------------> %Lu * %Lu = %Lu", 512 * fs->sects_clust, fs->max_clust - fs->fs_type, (512 * fs->sects_clust) * (fs->max_clust - fs->fs_type ));
fprintf( MONITOR_SERIAL, "\n\r4) Val3 = Val1 * Val2 ------------------------> %Lu * %Lu = %Lu", Val1, Val2, Val1 * Val2);

SDCard.Size = 512 * fs->sects_clust * (fs->max_clust - fs->fs_type);
fprintf( MONITOR_SERIAL, "\n\rCard size: %Ld", SDCard.Size );

Screen output:
1) Val1 = 512 * fs->sects_clust ------------> 512 * 64 = 32768
2) Val2 = fs->max_clust - fs->fs_type -----> 976994 - 3 = 976991
3) Val3 = Val1 * Val2 ------------------------> 32768 * 976991 = 1949270016
4) Val3 = Val1 * Val2 ------------------------> 42949705728 * 976991 = 41961475948904448
Card size: 1949270016

This code returns the proper numbers when I insert a 2GB and 4GB. Also note the two Val3 calculations: both use Val1 but the first one uses the calculation '32768 * 976991' and the other uses the direct 'Val1' variable. Both return different results.

I'm confused.

Thanks!

Ben

[EDIT] All I want, honestly, is to be able to make a calculation like 32768 * 976991 and get the correct answer printed and in the variable. The answer to this calculation should be 32,014,041,088.


Last edited by benoitstjean on Thu Oct 15, 2020 6:57 am; edited 1 time in total
temtronic



Joined: 01 Jul 2010
Posts: 9245
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 2:22 pm     Reply with quote

It 'might ' be a compiler version problem... Heck I can't do int64 ! got an old compiler.... I'll bet Mr. T. KNOWS the answers though !!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 2:47 pm     Reply with quote

976991 * 32768 = 0x7 742F 8000


Take off the leading '7' and you get:
0x742F8000 = 1,949,270,016

So it's truncating anything above 32 bits.


The current CCS manual says this in the printf section:
Quote:
Longs in the printf may be 16 or 32 bit.

It doesn't say anything about printing 64-bit numbers.
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 3:05 pm     Reply with quote

Oh, smart man!

So then, is there a way to print 64 bit numbers? I mean, the compiler supports int64 numbers, printing a 64-bit number would be nice...

Any idea how to approach this?

Ben

[EDIT] I guess since the smallest card logically that should go in there is at least a 2GB, even if it was 1GB, I could always just divide whatever result by 10 so be able to print somewhat of the correct value, but the real value is whatever got calculated.... but any suggestion on how to print the 64 bit value is welcome!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 3:33 pm     Reply with quote

You could print the two halves of it in hex:
Code:

unsigned int64 temp = 32014041088;

printf("%lx %lx \r", temp>>32, temp & 0xFFFFFFFF);
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 7:43 pm     Reply with quote

Thanks PCM programmer.

The problem is that printing in hex will be no good for my users as they don't understand hex. Back to your code, check it out with the very odd results. Code related to your suggestion is in blue:
Code:

unsigned int64 Val3 = (512 * fs->sects_clust) * (fs->max_clust - fs->fs_type );
unsigned int64 temp = 32014041088;

fprintf( MONITOR_SERIAL, "\n\rVal3 = %Ld %Ld", Val3>>32, Val3&0xFFFFFFFF );
fprintf( MONITOR_SERIAL, "\n\rVal3 = %lx %lx", Val3>>32, Val3&0xFFFFFFFF );

fprintf( MONITOR_SERIAL, "\n\rTemp = %Ld %Ld", temp>>32, temp&0xFFFFFFFF );
fprintf( MONITOR_SERIAL, "\n\rTemp = %lx %lx", temp>>32, temp&0xFFFFFFFF );


Output:

Val3 = 0 1949270016
Val3 = 0 742f8000
Temp = 7 1949270016
Temp = 7 742f8000


Now the question is why is the second part the same for both Val3 and Temp but the first part is not?? I mean, since both contain the same 'second part', it points to me that both Val3 and Temp are equal to 32014041088. I can easily calculate Val3 using the following values returned by the SD driver:

fs->fs_type: 3
fs->sects_clust: 64
fs->max_clust: 976994

unsigned int64 Val3 = (512 * fs->sects_clust) * (fs->max_clust - fs->fs_type );
512 * 64 * (976994 - 3 ) = 32768 * 976,991 = 32014041088

So both Val3 and Temp are the same value but yield different results? I'm at a loss here.

All I want is print the available size for the user to see but also so that the system knows what size of card it is using thus be able to calculate how much free space it has. Then when the space is running low, a message is sent-out to a user.

Thanks again.

Benoit
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 8:04 pm     Reply with quote

Cheat. Instead of printing the actual size, calculate the % free space and print that.

Code:
Capacity: 32GB, 43% free.


or:
Code:
Capacity: 8GB, <1% free.


You get the idea. So what if you can't print out, to the nearest byte, how much space remains. Numbers that large are meaningless to most people anyway. Or be creative: divide the real space remaining by 100. Then an int32 can account for up to ~400GB. So what if the last two digits are always "00"? Close enough. Work around the limits of the tools available to you.
jeremiah



Joined: 20 Jul 2010
Posts: 1355

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 8:22 pm     Reply with quote

According to the compiler manual, the itoa() function supports 64bit numbers. Have you tried using that to make a string, and then pass that into printf using %s?

Also note that the compiler manual states that 64bit numbers can only be signed, not unsigned. Even if you have code using unsigned 64bits that works, there is no guarantee it will work at edge cases or in the next compiler release.

itoa():
Code:

itoa( )
 
Syntax: 
string = itoa(i32value, i8base, string)
[PCD]  string = itoa(i48value, i8base, string)
[PCD]  string = itoa(i64value, i8base, string)

Parameters:
i32value is a 32 bit int

[PCD]  i48value is a 48 bit int
[PCD]  i64value is a 64 bit int

i8base is a 8 bit int

string is a pointer to a null terminated string of characters

Returns: 
string is a pointer to a null terminated string of characters



Basic Types:
Quote:

Note: All types, default are unsigned. [PCD] All types, except float char, by default are signed. However, may be preceded by unsigned or signed (Except int64 may only be signed) . Short and long may have the keyword INT following them with no effect. Also see #TYPE to change the default size.
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 8:43 pm     Reply with quote

Hi Newguy (makes me laugh, you've been around quite some time! Not new anymore!),

The biggest SD card that I can handle is 32GB. This equates to let's say 32,014,041,088 bytes depending on how it's formatted.

But I'm just wondering if the MCU can actually handle this big of a number. It's a 35-bit number.

This works:
[EDIT] Using a 4GB card for the example below.

float Percentage = ((float) SDCard.SpaceAvailable / (float) SDCard.Size ) * 100;
fprintf( MONITOR_SERIAL, "\n\r Available space: %3.1f %%", Percentage);

It displays:

Available space: 84.7 %

I guess I could live with this but I'd still like to know why I can't work with the 35-bit value of 32,014,041,088.

Off to bed, thanks to all, will attack this tomorrow morning.

Ben


Last edited by benoitstjean on Wed Oct 14, 2020 8:46 pm; edited 1 time in total
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 8:45 pm     Reply with quote

Hi Jeremiah,

Good point, I will try that tomorrow as well. Maybe if I can get the percentage working on the 32GB card (my last post was using a 4GB card), then I guess I could also play with the itoa function.

Good night and thank you for your time.

Ben
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Oct 14, 2020 8:55 pm     Reply with quote

Tried with the 32GB card and it doesn't like my int64 values:

int64 Size;
int64 SpaceAvailable;

I've put two approximate 530MB files on the card.

Total size: 1949270016 bytes (fprintf of Size variable)
Free space: 866319036 bytes (fprintf of SpaceAvailable variable)
Available space: 44.4 %

The calculation of 44.4% is fine using the numbers above but these are based on the values shown here which is a truncated version of the real number. They are int64, not unsigned int64.

So (866319036 / 1949270016 ) * 100 is in fact 44.4%..... but the card size is 32GB and the space available is around 31GB so 1/32 of the card is used.... not 44%.

Will investigate more tomorrow.

Ok, good night for real.

Ben
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Thu Oct 15, 2020 2:16 am     Reply with quote

itoa, does work. I have used it for int64's.

In your calculation, the 'total size' printout, is losing the '7' digit off the
front, so the total size is actually 0x700000000 larger than the printed
value.

1949270016 + 0x700000000 = 32014041088 (correct 32GB)

The percentage used, is then:

866319036/32014041088 *100 = 2.7%

Worth possibly just being 'aware', that the code I posted the other day
for adding commas to printed values, will work with an int64 value. You
could just omit the part that adds the commas if you don't want these....
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Thu Oct 15, 2020 6:12 am     Reply with quote

Hi Ttelmah,

Thanks for the details. That makes sense but tell me what is wrong here because it's still not displaying the correct value:

I didn't post the types for these variables (which are part of some other structure):
int8 fs->sects_clust
int32 fs->max_clust
int8 fs->fs_type


Code:

unsigned int64 temp = (512 * fs->sects_clust) * (fs->max_clust - fs->fs_type );
unsigned char Size[15] = "";
itoa( temp, 10, Size );

fprintf( MONITOR_SERIAL, "\n\r1) itoa = %s", Size );
fprintf( MONITOR_SERIAL, "\n\r2) Temp = %Ld", temp & 0x700000000 + temp & 0xFFFFFFFF );


Output:

1) itoa = 1949270016
2) Temp = 1949237248


So something is not liking over 32-bit numbers.... or else, what am I doing wrong? How can I display the darn number?

Ben
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Thu Oct 15, 2020 6:44 am     Reply with quote

'Classic'. Think about it.

fs->sects_clust is an int8.
512 is an int16.

So this multiplication is done using int16 maths and gives an int16 result.
You then multiply this by a value that is an int32. So int32 arithmetic will
be used..... Sad

You need:
unsigned int64 temp = (512 * fs->sects_clust) * (int64)(fs->max_clust - fs->fs_type );

Note the cast, which forces this value to be converted up to an int64.
Result int64 maths is then used....

Maths in C is always done using the 'higher' type of the values passed to
the operator. The size of the result has no effect on the maths size used.
Now some C's on things like the PC, implicitly use the floating point
coprocessor, and this does automatically convert values upwards. C's
on other platforms do not.
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Thu Oct 15, 2020 6:56 am     Reply with quote

Again, you saved the day.

I tried typecasting yesterday but I guess I didn't typecast to the correct type!

Total size: 32014041088 bytes
Free space: 30925863160 bytes
Available space: 96.6 %

Works!

Bravo! And thanks for all the others who picthed-in!

Ben
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group