Jump to content
Sign in to follow this  
Andreik

Definite Integrals

Recommended Posts

Andreik

I want to create a script and I need to compute defined integrals.

He's somebody who write a function to calculate defined integrals or how can I do that?

Thanks!


When the words fail... music speaks

Share this post


Link to post
Share on other sites
Andreik

I found an example but is written in C++

/* Copyright (C) Henry Golding, 2008. 
 * All rights reserved worldwide.
 *
 * This software is provided "as is" without express or implied
 * warranties. You may freely copy and compile this source into
 * applications you distribute provided that the copyright text
 * below is included in the resulting source code, for example:
 * "Portions Copyright (C) Henry Golding, 2008"
 */
#include <cassert>

// Returns the area of a trapezoid of a given height where sideA 
// and sideB are the uneven sides
float CalculateTrapezoidArea(float sideA, float sideB, float height)
{
    // Area of a trapezoid: A = (a+b)h / 2 (Wikipedia)
    return ( ( (sideA+sideB) * height  ) / 2.0f );
}

// Approximates the area under the curve of function pointed to by pFunc
// (which must take and return a float) in the range x=start to x=end. 
// Accuracy is determined by number of steps used between these values. 
float ApproximateIntegral(float (*pFunc)(float), float start, float end, unsigned steps)
{
    // pFunc is a pointer to a function that takes and returns a float, which we will use as f(x).
    // The general method is to calculate points at step intervals and calculate area of
    // the trapezoid underneath then add areas together 

    int   i;    // counter
    float diff; // the difference between steps - used as trapezoid height later
    float* xValues = new float[steps + 2]; // start, end and steps in between
    float* yValues = new float[steps + 2]; // for calculated results

    // set start and end x values
    xValues[0] = start;
    xValues[steps + 1] = end;

    // Interpolate x values for number of steps
    // Loop from second element to penultimate element
    diff = (end - start) / (steps + 1);
    for (i = 1; i <= steps; ++i)        
    {
        xValues[i] = xValues[i - 1] + diff;
    }

    // now we have all the x values, calculate all corresponding y values (or f(x))
    for (i = 0; i < steps + 2; ++i)
    {
        yValues[i] = (*pFunc)(xValues[i]);
    }

    // now calculate the area under each trapezoid
    // a will be first y of pair, b will be second y, h will be diff from earlier
    float finalArea = 0.0f;

    // we always need to do n-1 traps where n is the number of points we have
    for (i = 0; i < steps + 1; ++i)
    {
        finalArea += CalculateTrapezoidArea(yValues[i], yValues[i+1], diff);
    }

    delete[] xValues;
    delete[] yValues;

    return finalArea;
}

// A test function which returns y = x^2 - 4
float test(float x)
{
    return (x * x) - 4.0f;
}

// Test harness for the integral calculation functions
int main()
{
    float result;

    // check trapezoid area
    // a = 5, b = 10, h = 3, result should = 22.5
    result = CalculateTrapezoidArea(5.0f, 10.0f, 3.0f);
    assert( result == 22.5f);

    // check integral calculation
    // result of y = x^2 - 4 is approx -10.67f between -2 and 2
    result = ApproximateIntegral(test, -2.0f, 2.0f, 1);
    assert( result == -8.0f ); // correct calculation but only one step so very inaccurate

    result = ApproximateIntegral(test, -2.0f, 2.0f, 1000);
    assert( result == -10.666637f ); //more accurate

    return 0;
}

I wrote this in AutoIt, but is not so accurate:

Func TrapezoidArea($a,$b,$h)
    Return ((($a+$b)*$h)/2)
EndFunc

Func Integral($func,$x1,$x2,$step)
    Local $AREA = 0
    $func = StringLower($func)
    For $INDEX = $x1 To $x2 Step $step
        $valA = Execute(StringReplace($func,"x","$INDEX"))
        $valB = $valA + $step
        $AREA += TrapezoidArea($valA,$valB,$step)
    Next
    Return $AREA
EndFunc
Edited by Andreik

When the words fail... music speaks

Share this post


Link to post
Share on other sites
martin

Maybe the inacuracy is because you are calculating from $x1 To $x2 but you should calculate from $x1 To $x2 - $Step.


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites
Andreik

Now it's more better:

Func TrapezoidArea($a,$b,$h)
    Return ((($a+$b)*$h)/2)
EndFunc

Func Integral($FUNCTION,$X1,$X2,$STEP)
    Local $Area = 0
    Local $xValues[$STEP+2]
    Local $yValues[$STEP+2]
    $FUNCTION = StringLower($FUNCTION)
    $xValues[0] = $X1
    $xValues[$STEP+1] = $X2
    Local $DIFF = ($X2-$X1)/($STEP+1)
    For $INDEX = 1 To $STEP
        $xValues[$INDEX] = $xValues[$INDEX - 1] + $DIFF
    Next
    For $INDEX = 0 To $STEP+2
        If $INDEX >= $STEP+2 Then ExitLoop
        $yValues[$INDEX] = Execute(StringReplace($FUNCTION,"x","$xValues[$INDEX]"))
    Next
    For $INDEX = 0 To $STEP+1
        If $INDEX >= $STEP+1 Then ExitLoop
        $Area += TrapezoidArea($yValues[$INDEX],$yValues[$INDEX+1],$DIFF)
    Next
    Return Round($Area,5)
EndFunc

MsgBox(0,"",Integral("x",0,1,1000))
Edited by Andreik

When the words fail... music speaks

Share this post


Link to post
Share on other sites
martin

Your first approach looked simpler to me, but it needed a small change

Func TrapezoidArea($a,$b,$h)
    Return ((($a+$b)*$h)/2)
EndFunc

Func Integral($func,$x1,$x2,$step)
    Local $AREA = 0
    $func = StringLower($func)
    $last = Execute(StringReplace($func,"x",$x1))
    For $INDEX = $x1 + $step To $x2+$step Step $step
        $valA = Execute(StringReplace($func,"x","$INDEX"))
        $AREA += TrapezoidArea($valA,$last,$step)
        $last = $valA
    Next
     Return Round($Area,5)
EndFunc

MsgBox(0,"",Integral("x^2",0,1,.001000))

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites
Andreik

Your first approach looked simpler to me, but it needed a small change

Func TrapezoidArea($a,$b,$h)
    Return ((($a+$b)*$h)/2)
EndFunc

Func Integral($func,$x1,$x2,$step)
    Local $AREA = 0
    $func = StringLower($func)
    $last = Execute(StringReplace($func,"x",$x1))
    For $INDEX = $x1 + $step To $x2+$step Step $step
        $valA = Execute(StringReplace($func,"x","$INDEX"))
        $AREA += TrapezoidArea($valA,$last,$step)
        $last = $valA
    Next
     Return Round($Area,5)
EndFunc

MsgBox(0,"",Integral("x^2",0,1,.001000))
It`s more simple then second example but the second example it`s still more accurate.

Maybe if I change Round($Area,5) with Round($Area,2) will be better.

Please test the second example , looks to run in real time with a good result.

BTW I like your changes, it`s more simple. :mellow:

Edited by Andreik

When the words fail... music speaks

Share this post


Link to post
Share on other sites
martin

It`s more simple then second example but the second example it`s still more accurate.

Maybe if I change Round($Area,5) with Round($Area,2) will be better.

Please test the second example , looks to run in real time with a good result.

BTW I like your changes, it`s more simple. :mellow:

The version I gave had

For $INDEX = $x1 + $step To $x2 + $step Step $step

It should be

For $INDEX = $x1 + $step To $x2  Step $step

But for some values of $step the final loop seems not to get executed, so to ensure it is, and that another calculation isn't made beyond $x2 I tried this

For $INDEX = $x1 + $step To $x2 + $step/2 Step $step

That seems to improve it. Your second method still gives slightly different results (perhaps more accurate) sometimes but I don't see why.


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites
Andreik

The version I gave had

For $INDEX = $x1 + $step To $x2 + $step Step $step

It should be

For $INDEX = $x1 + $step To $x2  Step $step

But for some values of $step the final loop seems not to get executed, so to ensure it is, and that another calculation isn't made beyond $x2 I tried this

For $INDEX = $x1 + $step To $x2 + $step/2 Step $step

That seems to improve it. Your second method still gives slightly different results (perhaps more accurate) sometimes but I don't see why.

You are right, in my first example the distance between $x2-$step and $x2 is not executed, from here is the difference result.

In second example the range between $x1 and $x2 is divided exactly in several intervals, resulting greater accuracy.

Edited by Andreik

When the words fail... music speaks

Share this post


Link to post
Share on other sites
Malkey

This appears to work, also.

; Approximates the area under the curve of  $Equation
Local $Equation = "x^2 - 4"

Local $dfx = ApproxAreaUnderCurve(-2, 2, $Equation)
MsgBox(0, "", "Approximate Integral = " & $dfx)

; $Start,$End - The limits (start and end ) along x-axis
; $sEq is equation eg. "3*x^2 - 4*x + 4"
; $NoOfSteps ( Optional,default = 1000) Number of Trapezoids to use in calculation.
; (The higher the number of Trapezoids = The thinner the Trapezoids = The better the approximation of area)
; Returns the approximate area under a curve scribed by the equation, $sEq.
Func ApproxAreaUnderCurve($Start, $End, $sEq, $NoOfSteps = 10000)
    Local $xStep = ($End - $Start) / $NoOfSteps ; Individual step length along X-axis (Width of Trapezoid)
    ;ConsoleWrite(" $xStep = " & $xStep & @CRLF)
    Local $area
    Local $yLST = StringReplace($sEq, "x", "$x") ; Equation will return Left Side of Trapezoid (y value)
    ;ConsoleWrite( " $yLST = " & $yLST & @CRLF)
    Local $yRST = StringReplace($sEq, "x", "($x + $xStep)"); Equation will return Right Side of Trapezoid (y value)
    ;ConsoleWrite( " $yRST = " & $yRST & @CRLF)
    For $x = $Start To $End - $xStep Step $xStep
        $area += $xStep * (Execute($yLST) + Execute($yRST)) / 2 ; Accumulative areas of Trapezoids
    Next
    Return Round($area, 8)
EndFunc   ;==>ApproxAreaUnderCurve

Share this post


Link to post
Share on other sites
Andreik

This appears to work, also.

; Approximates the area under the curve of  $Equation
Local $Equation = "x^2 - 4"

Local $dfx = ApproxAreaUnderCurve(-2, 2, $Equation)
MsgBox(0, "", "Approximate Integral = " & $dfx)

; $Start,$End - The limits (start and end ) along x-axis
; $sEq is equation eg. "3*x^2 - 4*x + 4"
; $NoOfSteps ( Optional,default = 1000) Number of Trapezoids to use in calculation.
; (The higher the number of Trapezoids = The thinner the Trapezoids = The better the approximation of area)
; Returns the approximate area under a curve scribed by the equation, $sEq.
Func ApproxAreaUnderCurve($Start, $End, $sEq, $NoOfSteps = 10000)
    Local $xStep = ($End - $Start) / $NoOfSteps ; Individual step length along X-axis (Width of Trapezoid)
    ;ConsoleWrite(" $xStep = " & $xStep & @CRLF)
    Local $area
    Local $yLST = StringReplace($sEq, "x", "$x") ; Equation will return Left Side of Trapezoid (y value)
    ;ConsoleWrite( " $yLST = " & $yLST & @CRLF)
    Local $yRST = StringReplace($sEq, "x", "($x + $xStep)"); Equation will return Right Side of Trapezoid (y value)
    ;ConsoleWrite( " $yRST = " & $yRST & @CRLF)
    For $x = $Start To $End - $xStep Step $xStep
        $area += $xStep * (Execute($yLST) + Execute($yRST)) / 2 ; Accumulative areas of Trapezoids
    Next
    Return Round($area, 8)
EndFunc   ;==>ApproxAreaUnderCurve
Just tested. Work fine. Thanks Malkey! :mellow:

When the words fail... music speaks

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.