Active object: Difference between revisions
Content added Content deleted
Thundergnat (talk | contribs) (Undo revision 277235 by Thundergnat (talk) Wow, I completely screwed that up) |
Thundergnat (talk | contribs) m (Alphabetize; try this again) |
||
Line 1,260: | Line 1,260: | ||
v2 = it.runningsum |
v2 = it.runningsum |
||
println("After 2.5 seconds, integrator value was $v2")</lang> |
println("After 2.5 seconds, integrator value was $v2")</lang> |
||
=={{header|Lingo}}== |
|||
Parent script "Integrator": |
|||
<lang Lingo>property _sum |
|||
property _func |
|||
property _timeLast |
|||
property _valueLast |
|||
property _ms0 |
|||
property _updateTimer |
|||
on new (me, func) |
|||
if voidP(func) then func = "0.0" |
|||
me._sum = 0.0 |
|||
-- update frequency: 100/sec (arbitrary) |
|||
me._updateTimer = timeout().new("update", 10, #_update, me) |
|||
me.input(func) |
|||
return me |
|||
end |
|||
on stop (me) |
|||
me._updateTimer.period = 0 -- deactivates timer |
|||
end |
|||
-- func is a term (as string) that might contain "t" and is evaluated at runtime |
|||
on input (me, func) |
|||
me._func = func |
|||
me._ms0 = _system.milliseconds |
|||
me._timeLast = 0.0 |
|||
t = 0.0 |
|||
me._valueLast = value(me._func) |
|||
end |
|||
on output (me) |
|||
return me._sum |
|||
end |
|||
on _update (me) |
|||
now = _system.milliseconds - me._ms0 |
|||
t = now/1000.0 |
|||
val = value(me._func) |
|||
me._sum = me._sum + (me._valueLast+val)*(t - me._timeLast)/2 |
|||
me._timeLast = t |
|||
me._valueLast = val |
|||
end</lang> |
|||
In some movie script: |
|||
<lang Lingo>global gIntegrator |
|||
-- entry point |
|||
on startMovie |
|||
gIntegrator = script("Integrator").new("sin(PI * t)") |
|||
timeout().new("timer", 2000, #step1) |
|||
end |
|||
on step1 (_, timer) |
|||
gIntegrator.input("0.0") |
|||
timer.timeoutHandler = #step2 |
|||
timer.period = 500 |
|||
end |
|||
on step2 (_, timer) |
|||
gIntegrator.stop() |
|||
put gIntegrator.output() |
|||
timer.forget() |
|||
end</lang> |
|||
{{out}} |
|||
<pre>-- 0.0004</pre> |
|||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
Line 1,407: | Line 1,339: | ||
</pre> |
</pre> |
||
=={{header| |
=={{header|Lingo}}== |
||
Parent script "Integrator": |
|||
<lang Mathematica>Block[{start = SessionTime[], K, t0 = 0, t1, kt0, S = 0}, |
|||
<lang Lingo>property _sum |
|||
K[t_] = Sin[2 Pi f t] /. f -> 0.5; kt0 = K[t0]; |
|||
property _func |
|||
While[True, t1 = SessionTime[] - start; |
|||
property _timeLast |
|||
S += (kt0 + (kt0 = K[t1])) (t1 - t0)/2; t0 = t1; |
|||
property _valueLast |
|||
If[t1 > 2, K[t_] = 0; If[t1 > 2.5, Break[]]]]; S]</lang> |
|||
property _ms0 |
|||
property _updateTimer |
|||
on new (me, func) |
|||
1.1309*10^-6 |
|||
if voidP(func) then func = "0.0" |
|||
me._sum = 0.0 |
|||
-- update frequency: 100/sec (arbitrary) |
|||
me._updateTimer = timeout().new("update", 10, #_update, me) |
|||
me.input(func) |
|||
return me |
|||
end |
|||
on stop (me) |
|||
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. |
|||
me._updateTimer.period = 0 -- deactivates timer |
|||
end |
|||
-- func is a term (as string) that might contain "t" and is evaluated at runtime |
|||
=={{header|Oz}}== |
|||
on input (me, func) |
|||
<lang oz>declare |
|||
me._func = func |
|||
fun {Const X} |
|||
me._ms0 = _system.milliseconds |
|||
fun {$ _} X end |
|||
me._timeLast = 0.0 |
|||
end |
|||
t = 0.0 |
|||
me._valueLast = value(me._func) |
|||
end |
|||
on output (me) |
|||
fun {Now} |
|||
return me._sum |
|||
{Int.toFloat {Property.get 'time.total'}} / 1000.0 |
|||
end |
|||
on _update (me) |
|||
class Integrator from Time.repeat |
|||
now = _system.milliseconds - me._ms0 |
|||
attr |
|||
t = now/1000.0 |
|||
val = value(me._func) |
|||
me._sum = me._sum + (me._valueLast+val)*(t - me._timeLast)/2 |
|||
t1 k_t1 |
|||
me._timeLast = t |
|||
me._valueLast = val |
|||
end</lang> |
|||
meth init(SampleIntervalMS) |
|||
t1 := {Now} |
|||
k_t1 := {@k @t1} |
|||
{self setRepAll(action:Update |
|||
delay:SampleIntervalMS)} |
|||
thread |
|||
{self go} |
|||
end |
|||
end |
|||
In some movie script: |
|||
meth input(K) |
|||
<lang Lingo>global gIntegrator |
|||
k := K |
|||
end |
|||
-- entry point |
|||
meth output($) |
|||
on startMovie |
|||
@s |
|||
gIntegrator = script("Integrator").new("sin(PI * t)") |
|||
end |
|||
timeout().new("timer", 2000, #step1) |
|||
end |
|||
on step1 (_, timer) |
|||
meth Update |
|||
gIntegrator.input("0.0") |
|||
t2 := {Now} |
|||
timer.timeoutHandler = #step2 |
|||
k_t2 := {@k @t2} |
|||
timer.period = 500 |
|||
s := @s + (@k_t1 + @k_t2) * (@t2 - @t1) / 2.0 |
|||
end |
|||
t1 := @t2 |
|||
k_t1 := @k_t2 |
|||
end |
|||
end |
|||
on step2 (_, timer) |
|||
Pi = 3.14159265 |
|||
gIntegrator.stop() |
|||
put gIntegrator.output() |
|||
timer.forget() |
|||
end</lang> |
|||
{{out}} |
|||
I = {New Integrator init(10)} |
|||
<pre>-- 0.0004</pre> |
|||
in |
|||
{I input(fun {$ T} |
|||
{Sin 2.0 * Pi * F * T} |
|||
end)} |
|||
=={{header|Mathematica}}== |
|||
{Delay 2000} %% ms |
|||
<lang 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]</lang> |
|||
1.1309*10^-6 |
|||
{I input({Const 0.0})} |
|||
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. |
|||
{Delay 500} %% ms |
|||
{Show {I output($)}} |
|||
{I stop}</lang> |
|||
=={{header|ooRexx}}== |
=={{header|ooRexx}}== |
||
Line 1,560: | Line 1,498: | ||
</lang> |
</lang> |
||
=={{header|Perl}}== |
|||
<lang perl>#!/usr/bin/perl |
|||
use strict; |
|||
use 5.10.0; |
|||
package Integrator; |
|||
use threads; |
|||
use threads::shared; |
|||
sub new { |
|||
my $cls = shift; |
|||
my $obj = bless { t => 0, |
|||
sum => 0, |
|||
ref $cls ? %$cls : (), |
|||
stop => 0, |
|||
tid => 0, |
|||
func => shift, |
|||
}, ref $cls || $cls; |
|||
share($obj->{sum}); |
|||
share($obj->{stop}); |
|||
$obj->{tid} = async { |
|||
my $upd = 0.1; # update every 0.1 second |
|||
while (!$obj->{stop}) { |
|||
{ |
|||
my $f = $obj->{func}; |
|||
my $t = $obj->{t}; |
|||
$obj->{sum} += ($f->($t) + $f->($t + $upd))* $upd/ 2; |
|||
$obj->{t} += $upd; |
|||
} |
|||
select(undef, undef, undef, $upd); |
|||
} |
|||
# say "stopping $obj"; |
|||
}; |
|||
$obj |
|||
} |
|||
sub output { shift->{sum} } |
|||
sub delete { |
|||
my $obj = shift; |
|||
$obj->{stop} = 1; |
|||
$obj->{tid}->join; |
|||
} |
|||
sub setinput { |
|||
# This is surprisingly difficult because of the perl sharing model. |
|||
# Func refs can't be shared, thus can't be replaced by another thread. |
|||
# Have to create a whole new object... there must be a better way. |
|||
my $obj = shift; |
|||
$obj->delete; |
|||
$obj->new(shift); |
|||
} |
|||
package main; |
|||
my $x = Integrator->new(sub { sin(atan2(1, 1) * 8 * .5 * shift) }); |
|||
sleep(2); |
|||
say "sin after 2 seconds: ", $x->output; |
|||
$x = $x->setinput(sub {0}); |
|||
select(undef, undef, undef, .5); |
|||
say "0 after .5 seconds: ", $x->output; |
|||
$x->delete;</lang> |
|||
=={{header|Perl 6}}== |
|||
{{works with|Rakudo|2018.12}} |
|||
There is some jitter in the timer, but it is typically accurate to within a few thousandths of a second. |
|||
<lang perl6>class Integrator { |
|||
has $.f is rw = sub ($t) { 0 }; |
|||
has $.now is rw; |
|||
has $.value is rw = 0; |
|||
has $.integrator is rw; |
|||
method init() { |
|||
self.value = &(self.f)(0); |
|||
self.integrator = Thread.new( |
|||
:code({ |
|||
loop { |
|||
my $t1 = now; |
|||
self.value += (&(self.f)(self.now) + &(self.f)($t1)) * ($t1 - self.now) / 2; |
|||
self.now = $t1; |
|||
sleep .001; |
|||
} |
|||
}), |
|||
:app_lifetime(True) |
|||
).run |
|||
} |
|||
method Input (&f-of-t) { |
|||
self.f = &f-of-t; |
|||
self.init; |
|||
self.now = now; |
|||
} |
|||
method Output { self.value } |
|||
} |
|||
my $a = Integrator.new; |
|||
$a.Input( sub ($t) { sin(2 * π * .5 * $t) } ); |
|||
say "Initial value: ", $a.Output; |
|||
sleep 2; |
|||
say "After 2 seconds: ", $a.Output; |
|||
$a.Input( sub ($t) { 0 } ); |
|||
sleep .5; |
|||
say "f(0): ", $a.Output;</lang> |
|||
{{out|Typical output}} |
|||
<pre>Initial value: 0 |
|||
After 2 seconds: -0.0005555887464620366 |
|||
f(0): 0</pre> |
|||
=={{header|OxygenBasic}}== |
=={{header|OxygenBasic}}== |
||
Line 1,865: | Line 1,677: | ||
Rudolpho.clear</lang> |
Rudolpho.clear</lang> |
||
=={{header|Oz}}== |
|||
<lang 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}</lang> |
|||
=={{header|Perl}}== |
|||
<lang perl>#!/usr/bin/perl |
|||
use strict; |
|||
use 5.10.0; |
|||
package Integrator; |
|||
use threads; |
|||
use threads::shared; |
|||
sub new { |
|||
my $cls = shift; |
|||
my $obj = bless { t => 0, |
|||
sum => 0, |
|||
ref $cls ? %$cls : (), |
|||
stop => 0, |
|||
tid => 0, |
|||
func => shift, |
|||
}, ref $cls || $cls; |
|||
share($obj->{sum}); |
|||
share($obj->{stop}); |
|||
$obj->{tid} = async { |
|||
my $upd = 0.1; # update every 0.1 second |
|||
while (!$obj->{stop}) { |
|||
{ |
|||
my $f = $obj->{func}; |
|||
my $t = $obj->{t}; |
|||
$obj->{sum} += ($f->($t) + $f->($t + $upd))* $upd/ 2; |
|||
$obj->{t} += $upd; |
|||
} |
|||
select(undef, undef, undef, $upd); |
|||
} |
|||
# say "stopping $obj"; |
|||
}; |
|||
$obj |
|||
} |
|||
sub output { shift->{sum} } |
|||
sub delete { |
|||
my $obj = shift; |
|||
$obj->{stop} = 1; |
|||
$obj->{tid}->join; |
|||
} |
|||
sub setinput { |
|||
# This is surprisingly difficult because of the perl sharing model. |
|||
# Func refs can't be shared, thus can't be replaced by another thread. |
|||
# Have to create a whole new object... there must be a better way. |
|||
my $obj = shift; |
|||
$obj->delete; |
|||
$obj->new(shift); |
|||
} |
|||
package main; |
|||
my $x = Integrator->new(sub { sin(atan2(1, 1) * 8 * .5 * shift) }); |
|||
sleep(2); |
|||
say "sin after 2 seconds: ", $x->output; |
|||
$x = $x->setinput(sub {0}); |
|||
select(undef, undef, undef, .5); |
|||
say "0 after .5 seconds: ", $x->output; |
|||
$x->delete;</lang> |
|||
=={{header|Perl 6}}== |
|||
{{works with|Rakudo|2018.12}} |
|||
There is some jitter in the timer, but it is typically accurate to within a few thousandths of a second. |
|||
<lang perl6>class Integrator { |
|||
has $.f is rw = sub ($t) { 0 }; |
|||
has $.now is rw; |
|||
has $.value is rw = 0; |
|||
has $.integrator is rw; |
|||
method init() { |
|||
self.value = &(self.f)(0); |
|||
self.integrator = Thread.new( |
|||
:code({ |
|||
loop { |
|||
my $t1 = now; |
|||
self.value += (&(self.f)(self.now) + &(self.f)($t1)) * ($t1 - self.now) / 2; |
|||
self.now = $t1; |
|||
sleep .001; |
|||
} |
|||
}), |
|||
:app_lifetime(True) |
|||
).run |
|||
} |
|||
method Input (&f-of-t) { |
|||
self.f = &f-of-t; |
|||
self.init; |
|||
self.now = now; |
|||
} |
|||
method Output { self.value } |
|||
} |
|||
my $a = Integrator.new; |
|||
$a.Input( sub ($t) { sin(2 * π * .5 * $t) } ); |
|||
say "Initial value: ", $a.Output; |
|||
sleep 2; |
|||
say "After 2 seconds: ", $a.Output; |
|||
$a.Input( sub ($t) { 0 } ); |
|||
sleep .5; |
|||
say "f(0): ", $a.Output;</lang> |
|||
{{out|Typical output}} |
|||
<pre>Initial value: 0 |
|||
After 2 seconds: -0.0005555887464620366 |
|||
f(0): 0</pre> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |