1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice
Mosaic

Integer Percentage & ASM, no FP

This is a further discussion in the vein of 3v0's scaling article posted earlier. Percentage cal

  1. Mosaic
    • This update is currently awaiting approval.
    This is a further discussion in the vein of 3v0's scaling article posted earlier.

    Percentage calculations become necessary reasonably frequently, as a correction factor for sensors or for scaling numbers to fit on a limited digit display or any number of applications.

    Recently, I had reason to scale variable 8 bit numbers by a variable percentage in ASM. I also had a limitation of running the microcontroller at a low clock speed to be power efficient as a solar application.

    The key in maintaining reasonable accuracy is in using longer integers (2, 3 or 4byte. etc.) to do the calculations before finally dividing down to the result.

    For speed of calculation purposes I kept the scaling down to a 2 byte integer which also makes this discussion easier to implement.

    Eg. Correction percentage (calibration) factor to make 88 (an ADC reading) into 108.

    Actual % correction => (108-88)/88 = 20/88 = 22.7%

    A 16 bit integer can contain the product of 2, 8 bit integers, eg. 256*256 = 65536 values including 0, in most 8 bit calcs we tend to regard 255 as the max value held in an 8 bit integer as 0 is the zeroth value and 255 is the 256th value. Therefore for our purposes the max 16 bit integer value will be 255 * 255 = 65025 or about 2 ^15.99.

    We could attempt 'normal' 16 bit arithmetic by doing 88 + (20 * 88) /100 = 88 + 17 = 105, an integer error of about 3%.
    However, the division by 100 is problematic in terms of code and time efficiency and accuracy may be a problem.

    Exploiting binary arithmetic & byte value capacity is better:
    ;_________________________________________________________;
    As a prelude I point out that to multiply by 2.5 we multiply the original by 2 (shift bits left by 1) and add 1/2 the original value ( 1/2 = shift bits right by 1).

    Dividing a 16 bit (2 byte) integer by 256 simply takes the hi byte as the result. No 'calcs' needed.

    Multiplying by 33 requires a shift of 5 bits to the left and adding the original. Dividing by 32 (2^5) is a shift of 5 bits to the right.
    ;________________________________________________________;

    Using integer asm and binary shifts we can do:
    88+(20*88* 2.5)/256 = 105, with a similar 3% error. But much faster 8 bit division and acceptable noting that the numerator multiplication should use a 2 byte(16 bit result).

    If required for better than 3% accuracy we can also use integer math to 'correct' for the 3% error by 105 * 33/32 = 108.

    Thus accurate % calculations can be simply and efficiently done using pure 16 bit integer asm. This approach can be expanded to multi-byte integers for even greater precision.