Active object

From Rosetta Code

Jump to: navigation, search
Task
Active object
You are encouraged to solve this task according to the task description, using any language you may know.

In object-oriented programming an object is active when its state depends on clock. Usually an active object encapsulates a task that updates the object's state. To the outer world the object looks like a normal object with methods that can be called from outside. Implementation of such methods must have a certain synchronization mechanism with the encapsulated task in order to prevent object's state corruption.

A typical instance of an active object is an animation widget. The widget state changes with the time, while as an object it has all properties of a normal widget.

Contents

[edit] The task

Implement an active integrator object. The object has an input and output. The input can be set using the method Input. The input is a function of time. The output can be queried using the method Output. The object integrates its input over the time and the result becomes the object's output. So if the input is K(t) and the output is S, the object state S is changed to S + (K(t1) + K(t0)) * (t1 - t0) / 2, i.e. it integrates K using the trapeze method. Initially K is constant 0 and S is 0.

In order to test the object:

  1. set its input to sin (2π f t), where the frequency f=0.5Hz. The phase is irrelevant.
  2. wait 2s
  3. set the input to constant 0
  4. wait 0.5s

Verify that now the object's output is approximately 0 (the sine has the period of 2s). The accuracy of the result will depend on the OS scheduler time slicing and the accuracy of the clock.

[edit] Ada

with Ada.Calendar;                       use Ada.Calendar;
with Ada.Numerics; use Ada.Numerics;
with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions;
with Ada.Text_IO; use Ada.Text_IO;
 
procedure Test_Integrator is
type Func is access function (T : Time) return Float;
 
function Zero (T : Time) return Float is
begin
return 0.0;
end Zero;
 
Epoch : constant Time := Clock;
 
function Sine (T : Time) return Float is
begin
return Sin (Pi * Float (T - Epoch));
end Sine;
 
task type Integrator is
entry Input (Value : Func);
entry Output (Value : out Float);
entry Shut_Down;
end Integrator;
 
task body Integrator is
K  : Func  := Zero'Access;
S  : Float := 0.0;
F0 : Float := 0.0;
F1 : Float;
T0 : Time  := Clock;
T1 : Time;
begin
loop
select
accept Input (Value : Func) do
K := Value;
end Input;
or accept Output (Value : out Float) do
Value := S;
end Output;
or accept Shut_Down;
exit;
else
T1 := Clock;
F1 := K (T1);
S  := S + 0.5 * (F1 + F0) * Float (T1 - T0);
T0 := T1;
F0 := F1;
end select;
end loop;
end Integrator;
 
I : Integrator;
S : Float;
begin
I.Input (Sine'Access);
delay 2.0;
I.Input (Zero'Access);
delay 0.5;
I.Output (S);
Put_Line ("Integrated" & Float'Image (S) & "s");
I.Shut_Down;
end Test_Integrator;

Sample output:

Integrated-5.34100E-05s

[edit] C

Works with: POSIX

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <pthread.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
 
double nullfunc(double t)
{
return 0.0;
}
 
double func1(double t)
{
return sin(2.0*M_PI*0.5*t);
}
 
typedef double (*objfunc)(double);
struct objhandle_s {
int terminate;
pthread_mutex_t access_S;
pthread_mutex_t access_I;
pthread_mutex_t access_t;
objfunc I;
pthread_t th;
double S;
double t;
double freq;
};
typedef struct objhandle_s objhandle_t;
typedef struct objhandle_s *objhandle;
 
void *the_integrator(void *n)
{
objhandle oh = (objhandle)n;
double ts = 1.0/oh->freq;
while(oh->terminate == 0)
{
usleep((useconds_t)(ts*1000000.0));
pthread_mutex_lock(&oh->access_S);
pthread_mutex_lock(&oh->access_t);
pthread_mutex_lock(&oh->access_I);
oh->S += ( oh->I(oh->t+ts) - oh->I(oh->t) )*ts/2.0;
oh->t += ts;
pthread_mutex_unlock(&oh->access_I);
pthread_mutex_unlock(&oh->access_t);
pthread_mutex_unlock(&oh->access_S);
}
}
 
void destroy_integrator(objhandle integrator)
{
integrator->terminate = 1;
pthread_join(integrator->th, NULL);
free(integrator);
}
 
double integrator_getsum(objhandle integrator)
{
return integrator->S;
}
 
void integrator_setinput(objhandle integrator, objfunc nif)
{
pthread_mutex_lock(&integrator->access_I);
integrator->I = nif;
pthread_mutex_unlock(&integrator->access_I);
}
 
objhandle create_integrator(double freq)
{
objhandle r;
 
r = malloc(sizeof(objhandle_t));
if ( r != NULL )
{
pthread_mutex_init(&r->access_S, NULL);
pthread_mutex_init(&r->access_I, NULL);
pthread_mutex_init(&r->access_t, NULL);
r->terminate = 0;
r->t = 0.0;
r->S = 0.0;
r->I = nullfunc;
r->freq = freq;
pthread_create(&r->th, NULL, the_integrator, (void *)r);
}
return r;
}
 
 
int main()
{
objhandle integrator;
double sint;
 
integrator = create_integrator(10.0);
integrator_setinput(integrator, func1);
sleep(2);
integrator_setinput(integrator, nullfunc);
usleep(500000);
sint = integrator_getsum(integrator);
printf("S = %lf\n", sint);
destroy_integrator(integrator);
return 0;
}

Mutex for S and t (time) exists in case one wants to implement functions to reset/set S (sum) and time (t) i.e. to reset or set the integrator to a particular state.

Output:

S = -0.015451

By increasing the precision of the integrator by increasing the "sampling frequency" you can take a better result; e.g. with create_integrator(100.0) I've obtained S = -0.000157.

[edit] Clojure

(ns active-object
(:import (java.util Timer TimerTask)))
 
(defn input [integrator k]
(send integrator assoc :k k))
 
(defn output [integrator]
(:s @integrator))
 
(defn tick [integrator t1]
(send integrator
(fn [{:keys [k s t0] :as m}]
(assoc m :s (+ s (/ (* (+ (k t1) (k t0)) (- t1 t0)) 2.0)) :t0 t1))))
 
(defn start-timer [integrator interval]
(let [timer (Timer. true)
start (System/currentTimeMillis)]
(.scheduleAtFixedRate timer
(proxy [TimerTask] []
(run [] (tick integrator (double (/ (- (System/currentTimeMillis) start) 1000)))))
(long 0)
(long interval))
#(.cancel timer)))
 
(defn test-integrator []
(let [integrator (agent {:k (constantly 0.0) :s 0.0 :t0 0.0})
stop-timer (start-timer integrator 10)]
(input integrator #(Math/sin (* 2.0 Math/PI 0.5 %)))
(Thread/sleep 2000)
(input integrator (constantly 0.0))
(Thread/sleep 500)
(println (output integrator))
(stop-timer)))
 
user> (test-integrator)
1.414065859052494E-5
 

[edit] E

def makeIntegrator() {
var value := 0.0
var input := fn { 0.0 }
 
var input1 := input()
var t1 := timer.now()
 
def update() {
def t2 := timer.now()
def input2 :float64 := input()
def dt := (t2 - t1) / 1000
 
value += (input1 + input2) * dt / 2
 
t1 := t2
input1 := input2
}
 
var task() {
update <- ()
task <- ()
}
task()
 
def integrator {
to input(new) :void { input := new }
to output() :float64 { return value }
to shutdown() { task := fn {} }
}
return integrator
}
 
def test() {
def result
 
def pi := (-1.0).acos()
def freq := pi / 1000
 
def base := timer.now()
def i := makeIntegrator()
 
i.input(fn { (freq * timer.now()).sin() })
timer.whenPast(base + 2000, fn {
i.input(fn {0})
})
timer.whenPast(base + 2500, fn {
bind result := i.output()
i.shutdown()
})
return result
}

[edit] Factor

Working with dynamic quotations requires the stack effect to be known in advance. The apply-stack-effect serves this purpose.

USING: accessors alarms calendar combinators kernel locals math
math.constants math.functions prettyprint system threads ;
IN: rosettacode.active
 
TUPLE: active-object alarm function state previous-time ;
 
: apply-stack-effect ( quot -- quot' )
[ call( x -- x ) ] curry ; inline
 
: nano-to-seconds ( -- seconds ) nano-count 9 10^ / ;
 
: object-times ( active-object -- t1 t2 )
[ previous-time>> ]
[ nano-to-seconds [ >>previous-time drop ] keep ] bi ;
:: adding-function ( t1 t2 active-object -- function )
t2 t1 active-object function>> apply-stack-effect bi@ +
t2 t1 - * 2 / [ + ] curry ;
: integrate ( active-object -- )
[ object-times ]
[ adding-function ]
[ swap apply-stack-effect change-state drop ] tri ;
 
: <active-object> ( -- object )
active-object new
0 >>state
nano-to-seconds >>previous-time
[ drop 0 ] >>function
dup [ integrate ] curry 1 nanoseconds every >>alarm ;
: destroy ( active-object -- ) alarm>> cancel-alarm ;
 
: input ( object quot -- object ) >>function ;
: output ( object -- val ) state>> ;
 
: active-test ( -- )
<active-object>
[ 2 pi 0.5 * * * sin ] input
2 seconds sleep
[ drop 0 ] input
0.5 seconds sleep
[ output . ] [ destroy ] bi ;
MAIN: active-test
   ( scratchpad ) "rosettacode.active" run
   -5.294207647335787e-05

[edit] F#

open System
open System.Threading
 
// current time in seconds
let now() = float( DateTime.Now.Ticks / 10000L ) / 1000.0
 
type Integrator( intervalMs ) as x =
let mutable k = fun _ -> 0.0 // function to integrate
let mutable s = 0.0 // current value
let mutable t0 = now() // last time s was updated
let mutable running = true // still running?
 
do x.ScheduleNextUpdate()
 
member x.Input(f) = k <- f
 
member x.Output() = s
 
member x.Stop() = running <- false
 
member private x.Update() =
let t1 = now()
s <- s + (k t0 + k t1) * (t1 - t0) / 2.0
t0 <- t1
x.ScheduleNextUpdate()
 
member private x.ScheduleNextUpdate() =
if running then
async { do! Async.Sleep( intervalMs )
x.Update()
}
|> Async.Start
 
let i = new Integrator(10)
 
i.Input( fun t -> Math.Sin (2.0 * Math.PI * 0.5 * t) )
Thread.Sleep(2000)
 
i.Input( fun _ -> 0.0 )
Thread.Sleep(500)
 
printfn "%f" (i.Output())
i.Stop()

[edit] Go

Works with: gc version 2010-04-27

Using message passing trough channels for synchronization. It is also possible to use low-level synchronization, in the form of time.Sleep(), and sync.Mutex.

package main
 
import (
"fmt"
"time"
"math"
)
 
// boundle for output
type point struct {
value float64
time float64
}
 
type integrator struct {
// Internal state
input func(float64) float64
ticker *time.Ticker
accumulator float64
startTime float64
lastTime float64
lastValue float64
 
// World interaction (message passing)
inputUpdater chan func(float64) float64
stopper chan bool
outputReader chan point
}
 
func NewIntegrator(frequency float64) *integrator {
i := new(integrator)
 
// t -> 0
i.input = func(float64) float64 {
return 0
}
i.ticker = time.NewTicker(int64(1.0e+9/frequency))
 
i.accumulator = 0
i.startTime = float64(time.Nanoseconds()) * 1.0e-9
i.lastTime = 0
i.lastValue = i.input(0)
 
i.inputUpdater = make(chan func(float64) float64)
i.stopper = make(chan bool)
i.outputReader = make(chan point)
 
// Run in parallel
go i.run()
 
return i
}
 
func (i *integrator) Output() (value float64,time float64) {
if i.outputReader == nil {
panic("Trying to read from an inactive integrator")
}
 
// read a value (blocking)
p := <-i.outputReader
value = p.value
time = p.time
 
return
}
 
func (i *integrator) Input(input func(float64) float64) {
if i.inputUpdater != nil {
// send new function (blocking)
i.inputUpdater <- input
}
}
 
func (i *integrator) Stop() {
if i.stopper != nil {
// send stop signal (blocking)
i.stopper <- true
}
}
 
func (i *integrator) run() {
for {
select { // Channel multiplexer
case ns := <-i.ticker.C:
// Integration step
t := float64(ns) * 1.0e-9 - i.startTime
v := i.input(t)
i.accumulator += (v + i.lastValue) * (t - i.lastTime) * 0.5
i.lastValue = v
i.lastTime = t
// Send output if possible (non-blocking)
_ = i.outputReader <- point{value:i.accumulator,time:t}
case f := <-i.inputUpdater:
// New input function
i.input = f
case _ = <-i.stopper:
// Time to stop
i.outputReader = nil
i.inputUpdater = nil
i.stopper = nil
return
}
}
}
 
func main() {
i := NewIntegrator(10) // 10 Hz samples
ticker := time.NewTicker(int64(0.1e+9)) // 0.1 sec intervals
var sval, tval float64
mainLoop:
for step := 0; ; step++ {
switch step {
case 0: // 0.0 sec
// t -> sin(2π * 0.5 * t)
i.Input(func(t float64) float64 {
return math.Sin(2*math.Pi * 0.5 * t)
})
case 20: // 2.0 sec
i.Input(func(float64) float64 {
return 0
})
case 25: // 2.5 sec
sval, tval = i.Output()
break mainLoop
}
// Wait for tick
<-ticker.C
}
fmt.Printf("S[t=%v] = %v\n", tval, sval)
ticker.Stop()
i.Stop()
}

[edit] Haskell

module Integrator (
newIntegrator, input, output, stop,
Time, timeInterval
) where
import Control.Concurrent (forkIO, threadDelay)
import Control.Concurrent.MVar (MVar, newMVar, modifyMVar_, modifyMVar, readMVar)
import Control.Exception (evaluate)
import Data.Time (UTCTime)
import Data.Time.Clock (getCurrentTime, diffUTCTime)
 
-- RC task
main = do let f = 0.5 {- Hz -}
t0 <- getCurrentTime
i <- newIntegrator
input i (\t -> sin(2*pi * f * timeInterval t0 t)) -- task step 1
threadDelay 2000000 {- µs -} -- task step 2
input i (const 0) -- task step 3
threadDelay 500000 {- µs -} -- task step 4
result <- output i
stop i
print result
 
---- Implementation ------------------------------------------------------
 
-- Utilities for working with the time type
type Time = UTCTime
type Func a = Time -> a
timeInterval t0 t1 = realToFrac $ diffUTCTime t1 t0
 
-- Type signatures of the module's interface
newIntegrator :: Fractional a => IO (Integrator a) -- Create an integrator
input :: Integrator a -> Func a -> IO () -- Set the input function
output :: Integrator a -> IO a -- Get the current value
stop :: Integrator a -> IO () -- Stop integration, don't waste CPU
 
-- Data structures
data Integrator a = Integrator (MVar (IntState a)) -- MVar is a thread-safe mutable cell
deriving Eq
data IntState a = IntState { func :: Func a, -- The current function
run :: Bool, -- Whether to keep going
value :: a, -- The current accumulated value
time :: Time } -- The time of the previous update
 
newIntegrator = do
now <- getCurrentTime
state <- newMVar $ IntState { func = const 0,
run = True,
value = 0,
time = now }
thread <- forkIO (intThread state) -- The state variable is shared between the thread
return (Integrator state) -- and the client interface object.
 
input (Integrator stv) f = modifyMVar_ stv (\st -> return st { func = f })
output (Integrator stv) = fmap value $ readMVar stv
stop (Integrator stv) = modifyMVar_ stv (\st -> return st { run = False })
-- modifyMVar_ takes an MVar and replaces its contents according to the provided function.
-- a { b = c } is record-update syntax: "the record a, except with field b changed to c"
 
-- Integration thread
intThread :: Fractional a => MVar (IntState a) -> IO ()
intThread stv = whileM $ modifyMVar stv updateAndCheckRun
-- modifyMVar is like modifyMVar_ but the function returns a tuple of the new value
-- and an arbitrary extra value, which in this case ends up telling whileM whether
-- to keep looping.
where updateAndCheckRun st = do
now <- getCurrentTime
let value' = integrate (func st) (value st) (time st) now
evaluate value' -- avoid undesired laziness
return (st { value = value', time = now }, -- updated state
run st) -- whether to continue
 
integrate :: Fractional a => Func a -> a -> Time -> Time -> a
integrate f value t0 t1 = value + (f t0 + f t1)/2 * dt
where dt = timeInterval t0 t1
 
-- Execute 'action' until it returns false.
whileM action = do b <- action; if b then whileM action else return ()

[edit] JavaScript

Translation of: E

function Integrator(sampleIntervalMS) {
var inputF = function () { return 0.0 };
var sum = 0.0;
 
var t1 = new Date().getTime();
var input1 = inputF(t1 / 1000);
 
function update() {
var t2 = new Date().getTime();
var input2 = inputF(t2 / 1000);
var dt = (t2 - t1) / 1000;
 
sum += (input1 + input2) * dt / 2;
 
t1 = t2;
input1 = input2;
}
 
var updater = setInterval(update, sampleIntervalMS);
 
return ({
input: function (newF) { inputF = newF },
output: function () { return sum },
shutdown: function () { clearInterval(updater) },
});
}

Test program as a HTML fragment:

<p><span id="a">Test running...</span> <code id="b">-</code></p>
 
<script type="text/javascript">
var f = 0.5;
 
var i = new Integrator(1);
var displayer = setInterval(function () { document.getElementById("b").firstChild.data = i.output() }, 100)
 
setTimeout(function () {
i.input(function (t) { return Math.sin(2*Math.PI*f*t) }); // test step 1
setTimeout(function () { // test step 2
i.input(function (t) { return 0 }); // test step 3
setTimeout(function () { // test step 3
i.shutdown();
clearInterval(displayer);
document.getElementById("a").firstChild.data = "Done, should be about 0: "
}, 500);
}, 2000);
}, 1)
</script>

[edit] Mathematica

Block[{start = SessionTime[], K, t0 = 0, t1, kt0, S = 0}, 
K[t_] = Sin[2 Pi f t] /. f -> 0.5; kt0 = K[t0];
While[True, t1 = SessionTime[] - start;
S += (kt0 + (kt0 = K[t1])) (t1 - t0)/2; t0 = t1;
If[t1 > 2, K[t_] = 0; If[t1 > 2.5, Break[]]]]; S]
1.1309*10^-6

Curiously, this value never changes; it is always exactly the same (at 1.1309E-6). Note that closer answers could be achieved by using Mathematica's better interpolation methods, but it would require collecting the data (in a list), which would have a speed penalty large enough to negate the improved estimation.

[edit] Oz

declare
fun {Const X}
fun {$ _} X end
end
 
fun {Now}
{Int.toFloat {Property.get 'time.total'}} / 1000.0
end
 
class Integrator from Time.repeat
attr
k:{Const 0.0}
s:0.0
t1 k_t1
t2 k_t2
 
meth init(SampleIntervalMS)
t1 := {Now}
k_t1 := {@k @t1}
{self setRepAll(action:Update
delay:SampleIntervalMS)}
thread
{self go}
end
end
 
meth input(K)
k := K
end
 
meth output($)
@s
end
 
meth Update
t2 := {Now}
k_t2 := {@k @t2}
s := @s + (@k_t1 + @k_t2) * (@t2 - @t1) / 2.0
t1 := @t2
k_t1 := @k_t2
end
end
 
Pi = 3.14159265
F = 0.5
 
I = {New Integrator init(10)}
in
{I input(fun {$ T}
{Sin 2.0 * Pi * F * T}
end)}
 
{Delay 2000} %% ms
 
{I input({Const 0.0})}
 
{Delay 500} %% ms
 
{Show {I output($)}}
{I stop}

[edit] PicoLisp

(load "@lib/math.l")
 
(class +Active)
# inp val sum usec
 
(dm T ()
(unless (assoc -100 *Run) # Install timer task
(task -100 100 # Update objects every 0.1 sec
(mapc 'update> *Actives) ) )
(=: inp '((U) 0)) # Set zero input function
(=: val 0) # Initialize last value
(=: sum 0) # Initialize sum
(=: usec (usec)) # and time
(push '*Actives This) ) # Install in notification list
 
(dm input> (Fun)
(=: inp Fun) )
 
(dm update> ()
(let (U (usec) V ((: inp) U)) # Get current time, calculate value
(inc (:: sum)
(*/
(+ V (: val)) # (K(t[1]) + K(t[0])) *
(- U (: usec)) # (t[1] - t[0]) /
2.0 ) ) # 2.0
(=: val V)
(=: usec U) ) )
 
(dm output> ()
(format (: sum) *Scl) ) # Get result
 
(dm stop> ()
(unless (del This '*Actives) # Removing the last active object?
(task -100) ) ) # Yes: Uninstall timer task
 
(de integrate () # Test it
(let Obj (new '(+Active)) # Create an active object
(input> Obj # Set input function
'((U) (sin (*/ pi U 1.0))) ) # to sin(π * t)
(wait 2000) # Wait 2 sec
(input> Obj '((U) 0)) # Reset input function
(wait 500) # Wait 0.5 sec
(prinl "Output: " (output> Obj)) # Print return value
(stop> Obj) ) ) # Stop active object

[edit] Python

Assignment is thread-safe in Python, so no extra locks are needed in this case.


from time import time, sleep
from threading import Thread
 
class Integrator(Thread):
'continuously integrate a function `K`, at each `interval` seconds'
def __init__(self, K=lambda t:0, interval=1e-4):
Thread.__init__(self)
self.interval = interval
self.K = K
self.S = 0.0
self.__run = True
self.start()
 
def run(self):
"entry point for the thread"
interval = self.interval
start = time()
t0, k0 = 0, self.K(0)
while self.__run:
sleep(interval)
t1 = time() - start
k1 = self.K(t1)
self.S += (k1 + k0)*(t1 - t0)/2.0
t0, k0 = t1, k1
 
def join(self):
self.__run = False
Thread.join(self)
 
if __name__ == "__main__":
from math import sin, pi
 
ai = Integrator(lambda t: sin(pi*t))
sleep(2)
print ai.S
ai.K = lambda t: 0
sleep(0.5)
print ai.S

[edit] Scala

object ActiveObject {
 
class Integrator {
 
import java.util._
import scala.actors.Actor._
 
case class Pulse(t: Double)
case class Input(k: Double => Double)
case object Output
case object Bye
 
val timer = new Timer(true)
var k: Double => Double = (_ => 0.0)
var s: Double = 0.0
var t0: Double = 0.0
 
val handler = actor {
loop {
react {
case Pulse(t1) => s += (k(t1) + k(t0)) * (t1 - t0) / 2.0; t0 = t1
case Input(k) => this.k = k
case Output => reply(s)
case Bye => timer.cancel; exit
}
}
}
 
timer.scheduleAtFixedRate(new TimerTask {
val start = System.currentTimeMillis
def run { handler ! Pulse((System.currentTimeMillis - start) / 1000.0) }
}, 0, 10) // send Pulse every 10 ms
 
def input(k: Double => Double) = handler ! Input(k)
def output = handler !? Output
def bye = handler ! Bye
}
 
def main(args: Array[String]) {
val integrator = new Integrator
integrator.input(t => Math.sin(2.0 * Math.Pi * 0.5 * t))
Thread.sleep(2000)
integrator.input(_ => 0.0)
Thread.sleep(500)
println(integrator.output)
integrator.bye
}
}

[edit] Tcl

Works with: Tcl version 8.6 or Library: TclOO

This implementation Tcl 8.6 for object support (for the active integrator object) and coroutine support (for the controller task). It could be rewritten to only use 8.5 plus the TclOO library.

package require Tcl 8.6
oo::class create integrator {
variable e sum delay tBase t0 k0 aid
constructor {{interval 1}} {
set delay $interval
set tBase [clock microseconds]
set t0 0
set e { 0.0 }
set k0 0.0
set sum 0.0
set aid [after $delay [namespace code {my Step}]]
}
destructor {
after cancel $aid
}
method input expression {
set e $expression
}
method output {} {
return $sum
}
method Eval t {
expr $e
}
method Step {} {
set aid [after $delay [namespace code {my Step}]]
set t [expr {([clock microseconds] - $tBase) / 1e6}]
set k1 [my Eval $t]
set sum [expr {$sum + ($k1 + $k0) * ($t - $t0) / 2.}]
set t0 $t
set k0 $k1
}
}
 
set pi 3.14159265
proc pause {time} {
yield [after [expr {int($time * 1000)}] [info coroutine]]
}
proc task {script} {
coroutine task_ apply [list {} "$script;set ::done ok"]
vwait done
}
task {
integrator create i
i input {sin(2*$::pi * 0.5 * $t)}
pause 2
i input { 0.0 }
pause 0.5
puts [format %.15f [i output]]
}

Sample output:

-0.000000168952702

[edit] Visual Basic .NET

Since this object is CPU intensive, shutting it down when done is crucial. To facilitate this, the IDisposable pattern was used.

Module Module1
 
Sub Main()
Using active As New Integrator
active.Operation = Function(t As Double) Math.Sin(2 * Math.PI * 0.5 * t)
Threading.Thread.Sleep(TimeSpan.FromSeconds(2))
Console.WriteLine(active.Value)
active.Operation = Function(t As Double) 0
Threading.Thread.Sleep(TimeSpan.FromSeconds(0.5))
Console.WriteLine(active.Value)
End Using
Console.ReadLine()
End Sub
 
End Module
 
Class Integrator
Implements IDisposable
 
Private m_Operation As Func(Of Double, Double)
Private m_Disposed As Boolean
Private m_SyncRoot As New Object
Private m_Value As Double
 
Public Sub New()
m_Operation = Function(void) 0.0
Dim t As New Threading.Thread(AddressOf MainLoop)
t.Start()
End Sub
 
Private Sub MainLoop()
Dim epoch = Now
Dim t0 = 0.0
Do
SyncLock m_SyncRoot
Dim t1 = (Now - epoch).TotalSeconds
m_Value = m_Value + (Operation(t1) + Operation(t0)) * (t1 - t0) / 2
t0 = t1
End SyncLock
Threading.Thread.Sleep(10)
Loop Until m_Disposed
End Sub
 
Public Property Operation() As Func(Of Double, Double)
Get
SyncLock m_SyncRoot
Return m_Operation
End SyncLock
End Get
Set(ByVal value As Func(Of Double, Double))
SyncLock m_SyncRoot
m_Operation = value
End SyncLock
End Set
End Property
 
Public ReadOnly Property Value() As Double
Get
SyncLock m_SyncRoot
Return m_Value
End SyncLock
End Get
End Property
 
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
m_Disposed = True
End Sub
 
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
 
End Class


Output: 0.000241446762282308 
Personal tools
Support