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

            Wikipedia:Vital articles Мазмуну Biography - Өмүр баян Philosophy and psychology - Философия жана психология Religion - Дин Social sciences - Коомдук илимдер Language and literature - Тил жана адабият Science - Илим Technology - Технология Arts and recreation - Искусство жана эс алуу History and geography - Тарых жана география Навигация менюсу

            Bruxelas-Capital Índice Historia | Composición | Situación lingüística | Clima | Cidades irmandadas | Notas | Véxase tamén | Menú de navegacióneO uso das linguas en Bruxelas e a situación do neerlandés"Rexión de Bruxelas Capital"o orixinalSitio da rexiónPáxina de Bruselas no sitio da Oficina de Promoción Turística de Valonia e BruxelasMapa Interactivo da Rexión de Bruxelas-CapitaleeWorldCat332144929079854441105155190212ID28008674080552-90000 0001 0666 3698n94104302ID540940339365017018237

            What should I write in an apology letter, since I have decided not to join a company after accepting an offer letterShould I keep looking after accepting a job offer?What should I do when I've been verbally told I would get an offer letter, but still haven't gotten one after 4 weeks?Do I accept an offer from a company that I am not likely to join?New job hasn't confirmed starting date and I want to give current employer as much notice as possibleHow should I address my manager in my resignation letter?HR delayed background verification, now jobless as resignedNo email communication after accepting a formal written offer. How should I phrase the call?What should I do if after receiving a verbal offer letter I am informed that my written job offer is put on hold due to some internal issues?Should I inform the current employer that I am about to resign within 1-2 weeks since I have signed the offer letter and waiting for visa?What company will do, if I send their offer letter to another company