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

Printing large numbers

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

Printing large numbers
PostPosted: Mon Nov 13, 2017 5:58 am     Reply with quote

I use PIC16F1829 and the compiled code uses around 20% RAM and 60% Flash.
From this page: https://www.ccsinfo.com/forum/viewtopic.php?t=56327&start=15
I want to test/evaluate some variable, calculations and see them on LCD or RS232. I use LCD for now.
I arrived to next subroutine:
Code:
float Calculate_Pess()
{
   float var1, var2, p;
    if (adc_P == 0x800000) // value in case temp measurement was disabled
        return 0;
    adc_P >>= 4;
   var1 = ((float)t_fine/2.0) - 64000.0;
   var2 = var1 * var1 * ((float)dig_P6) / 32768.0;
   var2 = var2 + var1 * ((float)dig_P5) * 2.0;
   var2 = (var2/4.0)+(((float)dig_P4) * 65536.0);
   var1 = (((float)dig_P3) * var1 * var1 / 524288.0 + ((float)dig_P2) * var1) / 524288.0;
   var1 = (1.0 + var1 / 32768.0)*((float)dig_P1);
   if (var1 == 0.0)
   {
   //return 0; // avoid exception caused by division by zero
   }
   p = 1048576.0 - (float)adc_P;
   p = (p - (var2 / 4096.0)) * 6250.0 / var1;
   var1 = ((float)dig_P9) * p * p / 2147483648.0;
   var2 = p * ((float)dig_P8) / 32768.0;
   p = p + (var1 + var2 + ((float)dig_P7)) / 16.0;
return p/100;
   
}

and I want to evaluate intermediate calculation for var1, var2 and p.
I use something like that:
Code:
    lcd_gotoxy(1,1);
    printf(lcd_putc, "%f",var1);
   
    lcd_gotoxy(1,2);
    printf(lcd_putc, "%f",var2);

The problem is that I got large numbers and they are shown incorrectly, wrong, I expect due to printf.
For example when the code arrives to “var2 = (var2/4.0)+(((float)dig_P4) * 65536.0);” the result seen on LCD is wrong.
I use the same hardware with another compiler and the same code and the result shown on LCD is good, double checked with manual calculation using a calculator. Therefore it must be a limitation of CCS, probably printf.
My question is how to print of LCD large numbers generated by the float var1, var2 and p calculations above?
temtronic



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

View user's profile Send private message

PostPosted: Mon Nov 13, 2017 6:12 am     Reply with quote

1st, you're missing a few closing brackets in a couple lines, which may be causing the compiler to calculate differently than how you want it to.

2nd, PICs are NOT good at floating point number crunching, never have, never will..tis the 'nature of the beast'. You can get better results(and a LOT faster) using integers.

3rd, when reporting problems like this, you should supply 2 or 3 examples of input data ,the result and the expected result.
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Mon Nov 13, 2017 6:15 am     Reply with quote

printf will print anything.

You problem is more likely to be _accuracy_. remember a 4 byte float (which is what you are using in CCS), only holds about 6 digits. Now values like:

2147483648.0;

are going to lose their last two digits. Mutliply this and errors start to rise.

When you tested, you were probably using a system with 8byte floats (like the PC by default). Result massively different values after the calculations....

Now the reason CCS does not use 8 byte floats, is illustrated by the code size this is producing.

Honestly you need to sit down and work out what you are actually doing. There are factors being used here in several places that would much better be handled using integer arithmetic...
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Mon Nov 13, 2017 8:01 am     Reply with quote

and as an 'add on' comment, the one known issue with printf, is a few versions ago, if you used an 'unsized' format (so %f), this could give oddities. 'Sized' formats like %7.3, work better.
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

For precision use ints
PostPosted: Mon Nov 13, 2017 10:30 am     Reply with quote

I once built a sonar system to measure ship hulls. They wanted the output in decimal meters. But internally the system did the measurement in 24 bit integer tenths of millimeters. Conversion to meters was only done at the output.

I often calculate temperatures in integer millidegrees, converting to decimal degrees only at the end.
_________________
The search for better is endless. Instead simply find very good and get the job done.
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Mon Nov 13, 2017 11:21 am     Reply with quote

and as the example is the BME820, if you read the manufacturers data sheets, they give examples of how to do all the arithmetic in integer.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Nov 14, 2017 6:56 am     Reply with quote

@temtronic
1) I do not think are missing any closing brackets, because the code is copy paste from a whole working code tested by myself.
2) Agree that I should avoid floats and stay with integers, but I just followed the working example from given link https://www.ccsinfo.com/forum/viewtopic.php?t=56327&start=15
3) The examples are in the code from the above link, particularly the above pressure subroutine with variables var1 and var2.
The end result is good and proper displayed on LCD, but the intermediate values of var1 and var2 are so long that are somehow trimmed and not proper displayed.

@ Ttelmah
The compiler version is 5.070.
I think that is the problem that you mentioned, with accuracy.
I thought that is a workaround to see those results on LCD or sent to RS232.
Maybe is it good to convert them in strings and show strings on LCD/RS232?
How would you do it if you would like to see the var1 and var2 values at different points in that pressure subroutine?

The code with float was taken as it was provided in the above link.
Indeed the datasheet:
https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf
shows on page 49 the compensation with floating point – the same as in CCS code example, and on page 50 shows with 32 bit fixed point, which I never tried, but makes sense to me.
Adafruit with Arduino example library for BME280 uses “int64_t” for var 1 and var2 in pressure subroutine:
https://github.com/adafruit/Adafruit_BME280_Library/blob/master/Adafruit_BME280.cpp

But some other Japanese guys seem smarter and implemented for PIC the “signed long int” for var1 and var2 :
https://github.com/fues/BME280/blob/master/BSE280.h
https://translate.google.com/translate?hl=en&sl=ja&u=http://www.eonet.ne.jp/~charmy/pic/pic2.html&prev=search
https://translate.google.com/translate?hl=en&sl=ja&u=http://ja0qon.my.coocan.jp/labo/PIC_KIT/16F1705_BME280_TEST01.html&prev=search

I will try that too.
But never the less, for such situations with long numbers that you want to see on LCD or RS232, how do you do it to avoid seeing them truncated?
temtronic



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

View user's profile Send private message

PostPosted: Tue Nov 14, 2017 7:35 am     Reply with quote

hmm I zoomed to 150% and recounted () pairs and they are all there! The green vs white is kinda hard for my old eyes and tends to blur. O and 0 look very similar to me as well.. getting old ain't much fun., sigh
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Tue Nov 14, 2017 8:05 am     Reply with quote

Try just adding a size to the %f format. It may be all that is needed.

Much better if you can use the int16/int32 versions. Be very careful, since 'signed long int', is probably a signed int32.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 2:17 am     Reply with quote

Maybe is a problem with how I declare the variables.
If I look at https://en.wikipedia.org/wiki/C_data_types , then I see:
unsigned long int = unsigned int32 = [0, 4,294,967,295] range
signed long int = signed int32 = [−2,147,483,647, +2,147,483,647] range

The CCS user manual page 40 shows the Type Specifiers:
https://www.ccsinfo.com/downloads/ccs_c_manual.pdf
saying long long is int32, so I guess I should use unsigned int32 and signed int32.
Let’s go practical.
I use on the same hardware, PIC16F1829 and LCD a similar code in XC8 and I get different (good) results.
Here is a part of the CCS code from pressure subroutine of the BME280:
Code:
signed int32 var1, var2, dig_P6, t_fine;
unsigned int32 p;

t_fine=105000;
dig_P6=-7;

var1 = (((signed int32)t_fine)>>1) - (unsigned int32)64000;
var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed int32)dig_P6);

lcd_gotoxy(1,1);
printf(lcd_putc, "%Ld",var1);
lcd_gotoxy(1,2);
printf(lcd_putc, "%Ld",var2);

I‘ve got on LCD:
var1=-11500
var2=-7368277

Then with next XC8 code:
Code:
signed long long var1, var2;
unsigned long long p;

FCL_TFINE=105000;
FCL_P6=-7;

var1 = (((signed long long)FCL_TFINE)>>1) - (unsigned long long)64000;
var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long long)FCL_P6);

I‘ve got on LCD:
var1=-11500
var2=-28245

Now, I have a problem here, the result of var2 (and more calculations steps follow later).
The right value for var2 is the last one -28245, I calculated it by hand using the Calculator from Windows PC.
The question is: is that error due to the declaration of the Type Specifiers or is due to printf?
How do I debug it and find what is the cause?
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 2:33 am     Reply with quote

It just cross to my mind next: the error might be from difference between "logical shift" vs. "arithmetical shift".
If that is the case, then how do I implement the proper shift operations?
But if that would be the case, then how come the humidity and temperature subroutines work fine and the use the same shift symbols?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 2:43 am     Reply with quote

While you were thinking that, I was doing this test at the same time.
Result:
Quote:
-11500
-28245

Test program:
Code:
#include <16F1829.h>
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

//====================================
void main(void)
{
signed int32 var1, var2, dig_P6, t_fine;
unsigned int32 p;

t_fine = 105000;
dig_P6 = -7;

var1 = (((signed int32)t_fine)>>1) - (unsigned int32)64000;
//var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed int32)dig_P6);

var2 = (((var1 / 4) * (var1 / 4)) >> 11) * ((signed int32)dig_P6);

printf("%Ld \r",var1);
printf("%Ld \r",var2);
printf("\r");


while(TRUE);
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 2:50 am     Reply with quote

Yes. I actually posted this in one of the threads about the chip.
If you read the K&R documentation, and the ANSI documentation both say that these shift are 'implementation specific', but the code assumes that these will handle.

Code:

signed int32 shift_arith_right(signed int32 value, signed int8 amount)
{
    int1 negative=FALSE;
    if (value<0)
    {
       negative=TRUE;
       value=-value;
    }
    if (amount<0)
      value<<=(-amount);
    else
      value>>=(amount);
    if (negative)
      return -value;
    return value;
}


Ensures that a signed value will shift correctly
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 3:02 am     Reply with quote

I think I arrived somewhere.
It seems the error came from that math shift usage.
Actually I have from you Ttelmah next suggestion in the past:
http://www.ccsinfo.com/forum/viewtopic.php?t=56248&postdays=0&postorder=asc&start=30
I used it now:
Code:
signed int32 math_shift(signed int32 x, signed int32 y)
{ //Perform a mathematical right shift on a signed value
   if (bit_test(x,31)) //if -ve
      return -(-x>>y); //convert sign, shift, and convert back
   return x>>y; //otherwise simple shift
}

Then the code goes like this:
Code:
signed int32 var1, var2, dig_P6, t_fine;
unsigned int32 p;

t_fine=105000;
dig_P6=-7;

math_shift(math_shift(var1,2)*math_shift(var1,2),11);
var1 = math_shift(((signed int32)t_fine),1) - (unsigned int32)64000;
var2 = math_shift(math_shift(var1,2)*math_shift(var1,2),11)* ((signed int32)dig_P6);

lcd_gotoxy(1,1);
printf(lcd_putc, "%Ld",var1);
lcd_gotoxy(1,2);
printf(lcd_putc, "%Ld",var2);

It looks ugly with that math_shift(x, y) having so many parenthesis, but it works, I got the proper result.
And the answer to the question “how come the humidity and temperature subroutines work fine and the use the same shift symbols?” might be “because perhaps by chance it worked only with positive numbers” and I got into troubles when I had to shift arithmetical negative numbers, which means the initial code for BME280 is not very consistent and gives anyway bad results the pressure subroutine done with integers and that’s why was used the float pressure compensation.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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