Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: write in numbers

  1. #1
    Junior Member
    Join Date
    May 2020
    Posts
    2

    write in numbers

    Hi, I am working on a calculator and of course, I have to be able to write in the numbers from the button presses. I know that you are able to multiply by 10 and then ad the next number. T.ex:
    Code:
    if (x = 0 && digitalRead(button4) == 1){
    y = 4;
    }
    
    else if (digitalRead(button4) == 1){
    y = y * 10 +4;
    }
    This might be an option but I also want to be able to use commas. My first idé was to store everything in a String and then convert it to a BigNumber (using the BigNumber library) but have no idé how to do that. I found the atoi function but that convert's it into an integer so I still can't use commas. Im sure you smart people on the forum can help me.

    Sincerely Tobias.

  2. #2
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    6,906
    You need a (bool) flag "comma pressed" that gets set to true when the user pressed the comma-button. And a counter which gets set to 1.
    Then:
    - If that flag is false, you multiply with 10 and add the new digit - exactly as you decribed.
    - if it is true: counter=counter * 10; number = number + (newdigit / counter)

    Start with data type "double", perhaps. Later you can read about better solutions. But start with a simple solution.

  3. #3
    Senior Member
    Join Date
    Feb 2015
    Location
    Finland
    Posts
    189
    I agree with Frank B.

    It turns out it is usually easier to construct the value using integer types, and convert it to double when needed for computation. One would use something like the following for inputting a new value:
    Code:
        uint64_t  base = 0;
        int       decimals = -1;
        bool      negative = false;
    
        if (sign change pressed) {
            negative = !negative;
    
        } else
        if (decimal point pressed) {
            if (decimals < 0) {
                decimals = 0;
            }
    
        } else
        if (digit d is pressed) {
            uint64_t  temp = (base * 10) + d;
            if (temp <= UINT64_C(999999999999999999)) {
                base = temp;
                if (decimals >= 0) {
                    ++decimals;
                }
            }
        }
    Essentially, 'base' contains the digits, 'negative' is true if it is negative, and 'decimals' is -1 if the number is an integer, and the position of the decimal point otherwise. (decimals == 0 means the decimal point is to the right of the value, decimals == 1 means the decimal point is just before the least significant digit, and so on.)

    Note that you cannot really just check if the pin corresponding to each button is in the pressed state, because you'll put the above in a loop, and it gets executed several times each second. Instead, you need to track the state of each button, and only run the above when the button state changes from not-pressed to pressed.

    When we need to use the value, we convert it to a double:
    Code:
    static double positive_power_of_ten(unsigned int n)
    {
        double  result = 1.0;
        double  factor = 10.0;
    
        // result = Product(10**(2**k[i]), i), for k[] such that sum(2**k[i], i) == n.
        while (n) {
            if (n & 1) {
                result *= factor;
            }
            n >>= 1;
            factor *= 10;
        }
    
        return result;
    }
    
    double  triplet_to_double(uint64_t base, int decimals, bool negative)
    {
        double result = (double)base;
    
        // Optional precision check:
        if ((uint64_t)result != base) {
            // Warning: double type does not have sufficient precision to represent this value; rounding will occur.
        }
    
        if (decimals > 0) {
            result /= positive_power_of_ten(decimals);
        }
    
        // If you had an additional power of ten exponent parameter, exp10, you'd apply it here:
        //     if (exp10 > 0) {
        //        result *= positive_power_of_ten(exp10);
        //     } else
        //     if (exp10 < 0) {
        //        result /= positive_power_of_ten(-exp10);
        //     }
    
        if (negative) {
            result = -result;
        }
    
        return result;
    }
    Normally, you do not need the inverse operation, because calculator results are not editable. If you do need it, the key is again in powers of ten; you want decimals to be the largest possible value for which round(abs(double)*positive_power_of_ten(decimals)) <= positive_power_of_ten(display_digits) , with display_digits being the number of digits you can display. The left side is then the base. Finally, to get rid of unnecessary trailing fractional zeroes (to turn say 1.25000 into 1.25), as long as (base > 0 && decimals > 0 && base % 10 == 0), divide base by ten and decrement decimals by one. That's about it.

    In more general terms, it might be interesting to implement a class for radix-10 floating point values. These have an integer mantissa m, and an integer power of ten p, so that they represent positive value v = m × 10p; with a separate negative flag. The uint32_t type would allow 9 digits of precision in the mantissa; and uint64_t type 18 digits. Most interestingly, an array of uint32_t limbs (radix-109) would allow 9N digits of precision, allowing the internal use of uint64_t for temporaries. Trigonometric functions could be implemented via CORDIC or series expansion. Base-10 logarithm could exploit log10(v) = p + log10(m), and natural logarithm use the iterative approach. Exponential function would use the traditional sum. Multiplying n and m-digit values yields an m+n digit result, which then needs to be divided by a suitable power of ten. Division uses long division.

  4. #4
    Junior Member
    Join Date
    May 2020
    Posts
    2
    Thank you both for the help. I came up with this code.
    Code:
    	if(latest_button_press != 0 && calculate[calculateAr] = 0){
    		calculate[calculateAr] = latest_button_press;
    		if(comma = true){
    			calculate[calculateAr] /= 10;
    			comma_amouth *= 10;
    		}
    	}
    	else if(latest_button_press != 0 && calculate[calculateAr] != 0 && comma = false){
    		calculate[calculateAr] = calculate[calculateAr] * 10 + latest_button_press;
    			}
    	else if(latest_button_press != 0 && calculate[calculateAr] != 0 && comma = true){
    		calculate[calculateAr] =(calculate[calculateAr] * 10 * comma_amouth + latest_button_press) / (comma_amouth * 10);
    		comma_amouth *= 10;
    	}
    	else{
    		buttonin(1);
    Where calculate is a double array with the stored value that will be calculated, 'calculateAr' stores what pise of the calculate array i am working on, latest_button_press stores what number button was pressed, comma_amouth stores how many commas their are so i then can multiply, ad the number and then diveid back to the right state. The buttonin is a int function that checks the value of the buttons. I haven't tested it yet because I don't have enough buttons nor a teensy. I have only worked with arduino uno's.

    This is the first time I have just the forum. Am I supposed to mark it as solved or just leave it?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •