PIC mathematical operations weird problemPIC uno32 SPI communication with sensorNTC Thermistor circuit, ADC conversion, compute temperaturePIC18f45k20 ADC - always returns zeroRatiometric ADC and conversion algorithmsThe 4-wire resistive touch is connected to the ADC's input but it doesn't give correct valueUsing a digital potentiometer in a voltage dividerfluctuating ADC Reading for 4-20mA Pressure transducer inputMeasuring input voltage with 3.3V ADC MCUA/D Input PIC24EPConvert ADC value to real voltage

Why doesn't WotC use established keywords on all new cards?

How wide is a neg symbol, how to get the width for alignment?

I'm in your subnets, golfing your code

Can a nothic's Weird Insight action discover secrets about a player character that the character doesn't know about themselves?

Independent, post-Brexit Scotland - would there be a hard border with England?

What is the difference between 'unconcealed' and 'revealed'?

Building a list of products from the elements in another list

Fitch Proof Question

Why didn't the check-in agent recognize my long term visa?

Why wasn't the Night King naked in S08E03?

Is there an idiom that support the idea that "inflation is bad"?

Would Hubble Space Telescope improve black hole image observed by EHT if it joined array of telesopes?

Why was the battle set up *outside* Winterfell?

In Avengers 1, why does Thanos need Loki?

Can hackers enable the camera after the user disabled it?

Would the Disguise Self spell be able to reveal hidden birthmarks/tattoos (of the person they're disguised as) to a character?

I need a disease

Shantae Dance Matching

How to model the curly cable part of the phone

Have I damaged my car by attempting to reverse with hand/park brake up?

How to apply differences on part of a list and keep the rest

Why do only some White Walkers shatter into ice chips?

Has a commercial or military jet bi-plane ever been manufactured?

Can you complete the sequence?



PIC mathematical operations weird problem


PIC uno32 SPI communication with sensorNTC Thermistor circuit, ADC conversion, compute temperaturePIC18f45k20 ADC - always returns zeroRatiometric ADC and conversion algorithmsThe 4-wire resistive touch is connected to the ADC's input but it doesn't give correct valueUsing a digital potentiometer in a voltage dividerfluctuating ADC Reading for 4-20mA Pressure transducer inputMeasuring input voltage with 3.3V ADC MCUA/D Input PIC24EPConvert ADC value to real voltage






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








3












$begingroup$


I am trying to display the voltage value on my specific GPIO pin. I use PIC18F26K83. I can read ADC value. ( I tested it and it gives correct results.) ADC_read() function gives me 12 bit number. Now in order to find the voltage value I need to follow this calculation:



adc_value*(4.9)*(11) / 4096 


My voltage reference is 4.9 V and I have a voltage divider 1/11. So I need to multiply the adc_value I get, with this:

4.9*11/4096 = 0.01315917968.

But when I multiply them like this, I get something incorrect:



int adc_value= adc_Read(0);
adc_value=adc_value*0.01315917968;


I supposed to get something around 11. ADC_Value is around 1100. But the result of this calculation becomes 2.... Where am I wrong with this calculation?










share|improve this question











$endgroup$











  • $begingroup$
    What is the input voltage value?
    $endgroup$
    – Chu
    Apr 24 at 6:15










  • $begingroup$
    It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
    $endgroup$
    – Günkut Ağabeyoğlu
    Apr 24 at 6:19







  • 2




    $begingroup$
    Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
    $endgroup$
    – pipe
    Apr 24 at 7:38










  • $begingroup$
    Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
    $endgroup$
    – Günkut Ağabeyoğlu
    Apr 24 at 7:42










  • $begingroup$
    "Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
    $endgroup$
    – Dmitry Grigoryev
    Apr 24 at 11:55

















3












$begingroup$


I am trying to display the voltage value on my specific GPIO pin. I use PIC18F26K83. I can read ADC value. ( I tested it and it gives correct results.) ADC_read() function gives me 12 bit number. Now in order to find the voltage value I need to follow this calculation:



adc_value*(4.9)*(11) / 4096 


My voltage reference is 4.9 V and I have a voltage divider 1/11. So I need to multiply the adc_value I get, with this:

4.9*11/4096 = 0.01315917968.

But when I multiply them like this, I get something incorrect:



int adc_value= adc_Read(0);
adc_value=adc_value*0.01315917968;


I supposed to get something around 11. ADC_Value is around 1100. But the result of this calculation becomes 2.... Where am I wrong with this calculation?










share|improve this question











$endgroup$











  • $begingroup$
    What is the input voltage value?
    $endgroup$
    – Chu
    Apr 24 at 6:15










  • $begingroup$
    It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
    $endgroup$
    – Günkut Ağabeyoğlu
    Apr 24 at 6:19







  • 2




    $begingroup$
    Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
    $endgroup$
    – pipe
    Apr 24 at 7:38










  • $begingroup$
    Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
    $endgroup$
    – Günkut Ağabeyoğlu
    Apr 24 at 7:42










  • $begingroup$
    "Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
    $endgroup$
    – Dmitry Grigoryev
    Apr 24 at 11:55













3












3








3





$begingroup$


I am trying to display the voltage value on my specific GPIO pin. I use PIC18F26K83. I can read ADC value. ( I tested it and it gives correct results.) ADC_read() function gives me 12 bit number. Now in order to find the voltage value I need to follow this calculation:



adc_value*(4.9)*(11) / 4096 


My voltage reference is 4.9 V and I have a voltage divider 1/11. So I need to multiply the adc_value I get, with this:

4.9*11/4096 = 0.01315917968.

But when I multiply them like this, I get something incorrect:



int adc_value= adc_Read(0);
adc_value=adc_value*0.01315917968;


I supposed to get something around 11. ADC_Value is around 1100. But the result of this calculation becomes 2.... Where am I wrong with this calculation?










share|improve this question











$endgroup$




I am trying to display the voltage value on my specific GPIO pin. I use PIC18F26K83. I can read ADC value. ( I tested it and it gives correct results.) ADC_read() function gives me 12 bit number. Now in order to find the voltage value I need to follow this calculation:



adc_value*(4.9)*(11) / 4096 


My voltage reference is 4.9 V and I have a voltage divider 1/11. So I need to multiply the adc_value I get, with this:

4.9*11/4096 = 0.01315917968.

But when I multiply them like this, I get something incorrect:



int adc_value= adc_Read(0);
adc_value=adc_value*0.01315917968;


I supposed to get something around 11. ADC_Value is around 1100. But the result of this calculation becomes 2.... Where am I wrong with this calculation?







pic adc c






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Apr 24 at 7:36









Mike

31714




31714










asked Apr 24 at 5:58









Günkut AğabeyoğluGünkut Ağabeyoğlu

19613




19613











  • $begingroup$
    What is the input voltage value?
    $endgroup$
    – Chu
    Apr 24 at 6:15










  • $begingroup$
    It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
    $endgroup$
    – Günkut Ağabeyoğlu
    Apr 24 at 6:19







  • 2




    $begingroup$
    Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
    $endgroup$
    – pipe
    Apr 24 at 7:38










  • $begingroup$
    Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
    $endgroup$
    – Günkut Ağabeyoğlu
    Apr 24 at 7:42










  • $begingroup$
    "Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
    $endgroup$
    – Dmitry Grigoryev
    Apr 24 at 11:55
















  • $begingroup$
    What is the input voltage value?
    $endgroup$
    – Chu
    Apr 24 at 6:15










  • $begingroup$
    It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
    $endgroup$
    – Günkut Ağabeyoğlu
    Apr 24 at 6:19







  • 2




    $begingroup$
    Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
    $endgroup$
    – pipe
    Apr 24 at 7:38










  • $begingroup$
    Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
    $endgroup$
    – Günkut Ağabeyoğlu
    Apr 24 at 7:42










  • $begingroup$
    "Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
    $endgroup$
    – Dmitry Grigoryev
    Apr 24 at 11:55















$begingroup$
What is the input voltage value?
$endgroup$
– Chu
Apr 24 at 6:15




$begingroup$
What is the input voltage value?
$endgroup$
– Chu
Apr 24 at 6:15












$begingroup$
It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 6:19





$begingroup$
It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 6:19





2




2




$begingroup$
Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
$endgroup$
– pipe
Apr 24 at 7:38




$begingroup$
Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
$endgroup$
– pipe
Apr 24 at 7:38












$begingroup$
Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 7:42




$begingroup$
Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 7:42












$begingroup$
"Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
$endgroup$
– Dmitry Grigoryev
Apr 24 at 11:55




$begingroup$
"Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
$endgroup$
– Dmitry Grigoryev
Apr 24 at 11:55










3 Answers
3






active

oldest

votes


















8












$begingroup$

Try dividing by 1/0.013159 => 76 instead.



8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.



You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.






share|improve this answer











$endgroup$








  • 1




    $begingroup$
    A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
    $endgroup$
    – Uwe
    Apr 24 at 8:34










  • $begingroup$
    You are absolutely correct, I blame it being early in the morning when I answered.
    $endgroup$
    – r_ahlskog
    Apr 24 at 8:37


















11












$begingroup$


Where am I wrong with this calculation?




To add to the other answers, and to come at this from a different direction:



The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.



If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:



adc_value*(4.9)*(11) / 4096 


For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):



(adc_value * (10 * 4.9 * 11)) / 4096 


which is the same as:



(adc_value * 539) / 4096 


For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:



(adc_value * 539) >> 12


(This will round down; if we want to round to the nearest integer, see below)



So now we have a calculation which avoids both non-integers and division.



Plugging in the values mentions in a comment to the question:



(1140 * 539) >> 12 = 150


150 in tenths of a volt = 15.0 V, which is the expected answer.



If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.




If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:



(x + 2048) >> 12


So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:



((adc_value * 539) + 2048) >> 12





share|improve this answer









$endgroup$








  • 1




    $begingroup$
    Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
    $endgroup$
    – Yet Another User
    Apr 24 at 21:49


















9












$begingroup$

adc_value=adc_value*0.01315917968;


This is a floating poínt calculation and you try to put the result in an int value.
Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.



float ADC_complete;





share|improve this answer









$endgroup$













    Your Answer






    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("schematics", function ()
    StackExchange.schematics.init();
    );
    , "cicuitlab");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "135"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2felectronics.stackexchange.com%2fquestions%2f435142%2fpic-mathematical-operations-weird-problem%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    8












    $begingroup$

    Try dividing by 1/0.013159 => 76 instead.



    8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.



    You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.






    share|improve this answer











    $endgroup$








    • 1




      $begingroup$
      A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
      $endgroup$
      – Uwe
      Apr 24 at 8:34










    • $begingroup$
      You are absolutely correct, I blame it being early in the morning when I answered.
      $endgroup$
      – r_ahlskog
      Apr 24 at 8:37















    8












    $begingroup$

    Try dividing by 1/0.013159 => 76 instead.



    8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.



    You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.






    share|improve this answer











    $endgroup$








    • 1




      $begingroup$
      A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
      $endgroup$
      – Uwe
      Apr 24 at 8:34










    • $begingroup$
      You are absolutely correct, I blame it being early in the morning when I answered.
      $endgroup$
      – r_ahlskog
      Apr 24 at 8:37













    8












    8








    8





    $begingroup$

    Try dividing by 1/0.013159 => 76 instead.



    8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.



    You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.






    share|improve this answer











    $endgroup$



    Try dividing by 1/0.013159 => 76 instead.



    8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.



    You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Apr 24 at 10:38

























    answered Apr 24 at 6:33









    r_ahlskogr_ahlskog

    26616




    26616







    • 1




      $begingroup$
      A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
      $endgroup$
      – Uwe
      Apr 24 at 8:34










    • $begingroup$
      You are absolutely correct, I blame it being early in the morning when I answered.
      $endgroup$
      – r_ahlskog
      Apr 24 at 8:37












    • 1




      $begingroup$
      A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
      $endgroup$
      – Uwe
      Apr 24 at 8:34










    • $begingroup$
      You are absolutely correct, I blame it being early in the morning when I answered.
      $endgroup$
      – r_ahlskog
      Apr 24 at 8:37







    1




    1




    $begingroup$
    A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
    $endgroup$
    – Uwe
    Apr 24 at 8:34




    $begingroup$
    A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
    $endgroup$
    – Uwe
    Apr 24 at 8:34












    $begingroup$
    You are absolutely correct, I blame it being early in the morning when I answered.
    $endgroup$
    – r_ahlskog
    Apr 24 at 8:37




    $begingroup$
    You are absolutely correct, I blame it being early in the morning when I answered.
    $endgroup$
    – r_ahlskog
    Apr 24 at 8:37













    11












    $begingroup$


    Where am I wrong with this calculation?




    To add to the other answers, and to come at this from a different direction:



    The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.



    If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:



    adc_value*(4.9)*(11) / 4096 


    For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):



    (adc_value * (10 * 4.9 * 11)) / 4096 


    which is the same as:



    (adc_value * 539) / 4096 


    For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:



    (adc_value * 539) >> 12


    (This will round down; if we want to round to the nearest integer, see below)



    So now we have a calculation which avoids both non-integers and division.



    Plugging in the values mentions in a comment to the question:



    (1140 * 539) >> 12 = 150


    150 in tenths of a volt = 15.0 V, which is the expected answer.



    If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.




    If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:



    (x + 2048) >> 12


    So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:



    ((adc_value * 539) + 2048) >> 12





    share|improve this answer









    $endgroup$








    • 1




      $begingroup$
      Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
      $endgroup$
      – Yet Another User
      Apr 24 at 21:49















    11












    $begingroup$


    Where am I wrong with this calculation?




    To add to the other answers, and to come at this from a different direction:



    The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.



    If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:



    adc_value*(4.9)*(11) / 4096 


    For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):



    (adc_value * (10 * 4.9 * 11)) / 4096 


    which is the same as:



    (adc_value * 539) / 4096 


    For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:



    (adc_value * 539) >> 12


    (This will round down; if we want to round to the nearest integer, see below)



    So now we have a calculation which avoids both non-integers and division.



    Plugging in the values mentions in a comment to the question:



    (1140 * 539) >> 12 = 150


    150 in tenths of a volt = 15.0 V, which is the expected answer.



    If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.




    If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:



    (x + 2048) >> 12


    So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:



    ((adc_value * 539) + 2048) >> 12





    share|improve this answer









    $endgroup$








    • 1




      $begingroup$
      Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
      $endgroup$
      – Yet Another User
      Apr 24 at 21:49













    11












    11








    11





    $begingroup$


    Where am I wrong with this calculation?




    To add to the other answers, and to come at this from a different direction:



    The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.



    If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:



    adc_value*(4.9)*(11) / 4096 


    For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):



    (adc_value * (10 * 4.9 * 11)) / 4096 


    which is the same as:



    (adc_value * 539) / 4096 


    For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:



    (adc_value * 539) >> 12


    (This will round down; if we want to round to the nearest integer, see below)



    So now we have a calculation which avoids both non-integers and division.



    Plugging in the values mentions in a comment to the question:



    (1140 * 539) >> 12 = 150


    150 in tenths of a volt = 15.0 V, which is the expected answer.



    If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.




    If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:



    (x + 2048) >> 12


    So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:



    ((adc_value * 539) + 2048) >> 12





    share|improve this answer









    $endgroup$




    Where am I wrong with this calculation?




    To add to the other answers, and to come at this from a different direction:



    The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.



    If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:



    adc_value*(4.9)*(11) / 4096 


    For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):



    (adc_value * (10 * 4.9 * 11)) / 4096 


    which is the same as:



    (adc_value * 539) / 4096 


    For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:



    (adc_value * 539) >> 12


    (This will round down; if we want to round to the nearest integer, see below)



    So now we have a calculation which avoids both non-integers and division.



    Plugging in the values mentions in a comment to the question:



    (1140 * 539) >> 12 = 150


    150 in tenths of a volt = 15.0 V, which is the expected answer.



    If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.




    If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:



    (x + 2048) >> 12


    So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:



    ((adc_value * 539) + 2048) >> 12






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Apr 24 at 13:31









    Steve MelnikoffSteve Melnikoff

    635410




    635410







    • 1




      $begingroup$
      Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
      $endgroup$
      – Yet Another User
      Apr 24 at 21:49












    • 1




      $begingroup$
      Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
      $endgroup$
      – Yet Another User
      Apr 24 at 21:49







    1




    1




    $begingroup$
    Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
    $endgroup$
    – Yet Another User
    Apr 24 at 21:49




    $begingroup$
    Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
    $endgroup$
    – Yet Another User
    Apr 24 at 21:49











    9












    $begingroup$

    adc_value=adc_value*0.01315917968;


    This is a floating poínt calculation and you try to put the result in an int value.
    Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.



    float ADC_complete;





    share|improve this answer









    $endgroup$

















      9












      $begingroup$

      adc_value=adc_value*0.01315917968;


      This is a floating poínt calculation and you try to put the result in an int value.
      Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.



      float ADC_complete;





      share|improve this answer









      $endgroup$















        9












        9








        9





        $begingroup$

        adc_value=adc_value*0.01315917968;


        This is a floating poínt calculation and you try to put the result in an int value.
        Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.



        float ADC_complete;





        share|improve this answer









        $endgroup$



        adc_value=adc_value*0.01315917968;


        This is a floating poínt calculation and you try to put the result in an int value.
        Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.



        float ADC_complete;






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Apr 24 at 6:38









        MikeMike

        31714




        31714



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Electrical Engineering Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2felectronics.stackexchange.com%2fquestions%2f435142%2fpic-mathematical-operations-weird-problem%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Club Baloncesto Breogán Índice Historia | Pavillón | Nome | O Breogán na cultura popular | Xogadores | Adestradores | Presidentes | Palmarés | Historial | Líderes | Notas | Véxase tamén | Menú de navegacióncbbreogan.galCadroGuía oficial da ACB 2009-10, páxina 201Guía oficial ACB 1992, páxina 183. Editorial DB.É de 6.500 espectadores sentados axeitándose á última normativa"Estudiantes Junior, entre as mellores canteiras"o orixinalHemeroteca El Mundo Deportivo, 16 setembro de 1970, páxina 12Historia do BreogánAlfredo Pérez, o último canoneiroHistoria C.B. BreogánHemeroteca de El Mundo DeportivoJimmy Wright, norteamericano do Breogán deixará Lugo por ameazas de morteResultados de Breogán en 1986-87Resultados de Breogán en 1990-91Ficha de Velimir Perasović en acb.comResultados de Breogán en 1994-95Breogán arrasa al Barça. "El Mundo Deportivo", 27 de setembro de 1999, páxina 58CB Breogán - FC BarcelonaA FEB invita a participar nunha nova Liga EuropeaCharlie Bell na prensa estatalMáximos anotadores 2005Tempada 2005-06 : Tódolos Xogadores da Xornada""Non quero pensar nunha man negra, mais pregúntome que está a pasar""o orixinalRaúl López, orgulloso dos xogadores, presume da boa saúde económica do BreogánJulio González confirma que cesa como presidente del BreogánHomenaxe a Lisardo GómezA tempada do rexurdimento celesteEntrevista a Lisardo GómezEl COB dinamita el Pazo para forzar el quinto (69-73)Cafés Candelas, patrocinador del CB Breogán"Suso Lázare, novo presidente do Breogán"o orixinalCafés Candelas Breogán firma el mayor triunfo de la historiaEl Breogán realizará 17 homenajes por su cincuenta aniversario"O Breogán honra ao seu fundador e primeiro presidente"o orixinalMiguel Giao recibiu a homenaxe do PazoHomenaxe aos primeiros gladiadores celestesO home que nos amosa como ver o Breo co corazónTita Franco será homenaxeada polos #50anosdeBreoJulio Vila recibirá unha homenaxe in memoriam polos #50anosdeBreo"O Breogán homenaxeará aos seus aboados máis veteráns"Pechada ovación a «Capi» Sanmartín e Ricardo «Corazón de González»Homenaxe por décadas de informaciónPaco García volve ao Pazo con motivo do 50 aniversario"Resultados y clasificaciones""O Cafés Candelas Breogán, campión da Copa Princesa""O Cafés Candelas Breogán, equipo ACB"C.B. Breogán"Proxecto social"o orixinal"Centros asociados"o orixinalFicha en imdb.comMario Camus trata la recuperación del amor en 'La vieja música', su última película"Páxina web oficial""Club Baloncesto Breogán""C. B. Breogán S.A.D."eehttp://www.fegaba.com

            Vilaño, A Laracha Índice Patrimonio | Lugares e parroquias | Véxase tamén | Menú de navegación43°14′52″N 8°36′03″O / 43.24775, -8.60070

            Cegueira Índice Epidemioloxía | Deficiencia visual | Tipos de cegueira | Principais causas de cegueira | Tratamento | Técnicas de adaptación e axudas | Vida dos cegos | Primeiros auxilios | Crenzas respecto das persoas cegas | Crenzas das persoas cegas | O neno deficiente visual | Aspectos psicolóxicos da cegueira | Notas | Véxase tamén | Menú de navegación54.054.154.436928256blindnessDicionario da Real Academia GalegaPortal das Palabras"International Standards: Visual Standards — Aspects and Ranges of Vision Loss with Emphasis on Population Surveys.""Visual impairment and blindness""Presentan un plan para previr a cegueira"o orixinalACCDV Associació Catalana de Cecs i Disminuïts Visuals - PMFTrachoma"Effect of gene therapy on visual function in Leber's congenital amaurosis"1844137110.1056/NEJMoa0802268Cans guía - os mellores amigos dos cegosArquivadoEscola de cans guía para cegos en Mortágua, PortugalArquivado"Tecnología para ciegos y deficientes visuales. Recopilación de recursos gratuitos en la Red""Colorino""‘COL.diesis’, escuchar los sonidos del color""COL.diesis: Transforming Colour into Melody and Implementing the Result in a Colour Sensor Device"o orixinal"Sistema de desarrollo de sinestesia color-sonido para invidentes utilizando un protocolo de audio""Enseñanza táctil - geometría y color. Juegos didácticos para niños ciegos y videntes""Sistema Constanz"L'ocupació laboral dels cecs a l'Estat espanyol està pràcticament equiparada a la de les persones amb visió, entrevista amb Pedro ZuritaONCE (Organización Nacional de Cegos de España)Prevención da cegueiraDescrición de deficiencias visuais (Disc@pnet)Braillín, un boneco atractivo para calquera neno, con ou sen discapacidade, que permite familiarizarse co sistema de escritura e lectura brailleAxudas Técnicas36838ID00897494007150-90057129528256DOID:1432HP:0000618D001766C10.597.751.941.162C97109C0155020