Thread: Formula Problem

  1. #1
    Registered User
    Join Date
    Sep 2013
    Location
    Cairns, Australia
    Posts
    8

    Formula Problem

    I have a formula that gives the correct result in C++ Builder, but not in AVR Studio 6.0. I am at loss as to why this is the case.

    Below is the code.

    Ray.

    Code:
    uint16_t x1, x2, y1, y2;
        uint16_t Q11, Q12, Q21, Q22;
        uint16_t xAxis, yAxis;
        float InterpVal;
        uint16_t finalValue;
        
        x1 = 1000;
        x2 = 2000;
        y1 = 400;
        y2 = 600;
        Q11 = 0;
        Q12 = 0;
        Q21 = 100;
        Q22 = 200;
        xAxis = 1500;
        yAxis = 450;
        
        InterpVal = (float)(((x2 - xAxis) * (y2 - yAxis)) / (float)((x2 - x1) * (y2 - y1)) * Q11) +
                    (float)(((xAxis - x1) * (y2 - yAxis)) / (float)((x2 - x1) * (y2 - y1)) * Q21) +
                    (float)(((x2 - xAxis) * (yAxis - y1)) / (float)((x2 - x1) * (y2 - y1)) * Q12) +
                    (float)(((xAxis - x1) * (yAxis - y1)) / (float)((x2 - x1) * (y2 - y1)) * Q22);
    
        finalValue = (uint16_t)InterpVal;    // Gives the value 1753 when 62 is the correct value.

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    I don't see anything wrong.
    How exactly are you printing the value?
    A uint16_t is not necessarily the same as an unsigned short, so if you're just using %hu that could be the problem.
    Try
    Code:
        printf("%"PRIu16"\n", finalValue);  // include <inttypes.h>
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  3. #3
    Registered User
    Join Date
    Sep 2013
    Location
    Cairns, Australia
    Posts
    8
    Quote Originally Posted by oogabooga View Post
    I don't see anything wrong.
    How exactly are you printing the value?
    A uint16_t is not necessarily the same as an unsigned short, so if you're just using %hu that could be the problem.
    Try
    Code:
        printf("%"PRIu16"\n", finalValue);  // include <inttypes.h>
    The returned value is used in other code that controls a H-Bridge motor. In this case the motor is driven incorectly. When sent via serial USB the value is wrong. When sent to a LCD display it is wrong also.

    The same code used in C++ Builder gives the correct value.

    This is my full embedded test code that sends the value to a LCD display.

    Code:
    #define F_CPU 1000000UL
    #include <avr/io.h>
    #include <util/delay.h>
    #include "lcd.h"
    
    void init_Things(void)
    {
        lcd_init(LCD_DISP_ON);
        lcd_clrscr();
    
        _delay_ms(10);
    }
    
    int main(void)
    {
        init_Things();
        
        char buffer[10];
        char buf[10];
        strcpy(buffer, "Value: ");  
        
        uint16_t x1, x2, y1, y2;
        uint16_t Q11, Q12, Q21, Q22;
        uint16_t xAxis, yAxis;
        float InterpVal;
        uint16_t finalValue;
        
        x1 = 1000;
        x2 = 2000;
        y1 = 400;
        y2 = 600;
        Q11 = 0;
        Q12 = 0;
        Q21 = 100;
        Q22 = 200;
        xAxis = 1500;
        yAxis = 450;
        
        InterpVal = (float)(((x2 - xAxis) * (y2 - yAxis)) / (float)((x2 - x1) * (y2 - y1)) * Q11) +
                    (float)(((xAxis - x1) * (y2 - yAxis)) / (float)((x2 - x1) * (y2 - y1)) * Q21) +
                    (float)(((x2 - xAxis) * (yAxis - y1)) / (float)((x2 - x1) * (y2 - y1)) * Q12) +
                    (float)(((xAxis - x1) * (yAxis - y1)) / (float)((x2 - x1) * (y2 - y1)) * Q22);
    
        finalValue = (uint16_t)InterpVal;    // Gives the value 1753 when 62 is the correct value.
        
        utoa(finalValue, buf,10);
        strcat(buffer, buf);
        lcd_gotoxy(0,0);
        lcd_puts(buffer);
        
        
        while(1)
        {
            //TODO:: Please write your application code 
        }
    }

  4. #4
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Try this:
    Code:
    utoa((unsigned)finalValue, buf,10);
    

    Let me know if it works.

    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  5. #5
    Registered User
    Join Date
    Sep 2013
    Location
    Cairns, Australia
    Posts
    8
    Quote Originally Posted by oogabooga View Post
    Try this:
    Code:
    utoa((unsigned)finalValue, buf,10);
    

    Let me know if it works.

    No change still get 1753.

    Ray.

  6. #6
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    After I posted it I realized that it wasn't going to work since the promotion would occur automatically.
    I'm stumped. Hopefully someone else can give you an answer.

    Are you compiling with the highest warning level available?
    Last edited by oogabooga; 09-16-2013 at 04:52 PM.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  7. #7
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Take one subexpression from your formula (in this case the numerator portion on line 39 in post #3):
    Code:
    ((x2 - xAxis) * (y2 - yAxis))
    Substituting values gives:
    Code:
    (2000 - 1500) * (600 - 450) = 500 * 150 = 75000
    75000 is too big to fit in a 16 bits. Depending on how the compiler evaluates the different parts of the expression, it may be trying to store that value in a 16 register for further computations. The overflow could mess up the rest of the computation. Try making everything a uin32_t instead and see if that helps.

    EDIT: Everything but finalVal I guess, since whatever uses that value expects only 16 bits.
    Last edited by anduril462; 09-16-2013 at 05:36 PM.

  8. #8
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    My first suggestion would be to break apart that large calculation into individual variables so you can check each part.

    Also with the numbers given you can comment out the first and third part of the equation, since they will equal zero with the numbers provided.


    Code:
    ...
       uint16_t first, second, third, fourth;
    ...
       first = xAxis - x1;
       second = y2 - yAxis;
       third = x2 - x1;
       fourth = y2 - y1;
    
        InterpVal = /*(float)(((x2 - xAxis) * (y2 - yAxis)) / (float)((x2 - x1) * (y2 - y1)) * Q11) + */
                    (float)(((xAxis - x1) * (y2 - yAxis)) / (float)((x2 - x1) * (y2 - y1)) * Q21) +
                   /* (float)(((x2 - xAxis) * (yAxis - y1)) / (float)((x2 - x1) * (y2 - y1)) * Q12) + */
                    (float)(((xAxis - x1) * (yAxis - y1)) / (float)((x2 - x1) * (y2 - y1)) * Q22);
    Look at each individual part of the equation, looking for numbers that may overflow the type. Your float casts are spanning several of these calculations so the intermediate calculations may still be a problem.

    And be sure that all the required include files have been included. Something like:

    Code:
    #include <stdint.h>
    #include <string.h>
    #include <stdlib.h>
    #include <inttypes.h>
    #include <stdio.h>
    I included stdio.h in order to use printf() but you may not be able to use printf() on your embedded system so you may not need this header.

    Jim

  9. #9
    Registered User
    Join Date
    Sep 2013
    Location
    Cairns, Australia
    Posts
    8
    Quote Originally Posted by anduril462 View Post
    Take one subexpression from your formula (in this case the numerator portion on line 39 in post #3):
    Code:
    ((x2 - xAxis) * (y2 - yAxis))
    Substituting values gives:
    Code:
    (2000 - 1500) * (600 - 450) = 500 * 150 = 75000
    75000 is too big to fit in a 16 bits. Depending on how the compiler evaluates the different parts of the expression, it may be trying to store that value in a 16 register for further computations. The overflow could mess up the rest of the computation. Try making everything a uin32_t instead and see if that helps.

    EDIT: Everything but finalVal I guess, since whatever uses that value expects only 16 bits.

    Changed them to uint32_t except for finalVal and I now get the correct value....Very happy..

    Thank you for your help.

    Ray.

  10. #10
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Just to complete this topic, it worked on the PC because uint16_t's are converted to ints during the calculations and ints are at least 32-bits. But in the 8-bit Atmel AVR, ints are presumably only 16-bits so the uint16_t's would be used as-is unless you explicitly tell it to do otherwise.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Formula for Running word problem
    By fren-z-on3 in forum C++ Programming
    Replies: 3
    Last Post: 02-16-2010, 04:42 PM
  2. C program formula code problem
    By parachutes89 in forum C Programming
    Replies: 5
    Last Post: 09-14-2009, 04:13 AM
  3. Anyone know how to use this formula?
    By gator6688 in forum C++ Programming
    Replies: 3
    Last Post: 11-09-2007, 10:42 PM
  4. Problem with a mathematical formula
    By BianConiglio in forum C Programming
    Replies: 13
    Last Post: 04-29-2005, 11:26 PM
  5. Formula problem
    By Cassius in forum C++ Programming
    Replies: 4
    Last Post: 10-05-2002, 04:54 PM