#! perl -slw use strict; $| = 1; package FET; our @EXPORT = 'pCutoff'; use List::Util qw[ sum reduce ]; sub toRatio; sub rpCutoff; sub rdivide; sub fac; sub rtimes; sub cancel; sub merge; sub pCutoff; sub pCutoff{ toRatio rpCutoff @_ } sub rpCutoff { my @rs = map{ sum @$_ } @_; my @cs = map{ sum @$_ } [ $_[0][0], $_[1][0] ], [ $_[0][1], $_[1][1] ]; my $n = sum @rs; my @xs = map{ @$_ } @_; rdivide facproduct( @rs, @cs ), facproduct( $n, @xs ); } sub rproduct{ reduce{ rtimes $a, $b } [[],[]], @_ } sub facproduct{ rproduct map{ fac $_ } @_ } sub fac{ $_[0] < 2 ? [[],[]] : [[ 2 .. $_[0] ], []]; } sub toRatio{ [ bigProduct( $_[0][0] ), bigProduct( $_[0][1] ) ] } sub bigProduct{ reduce{ $a * $b } map{ @$_ } @_ } sub rdivide{ rtimes $_[0], [ $_[1][1], $_[1][0] ] } sub rtimes{ [ cancel merge($_[0][0], $_[1][0]), merge($_[0][1], $_[1][1] )] } sub merge; sub merge{ return $_[1] unless defined $_[0] and @{ $_[0] }; return $_[0] unless defined $_[1] and @{ $_[1] }; my( $x, @xs ) = @{ $_[0] }; my( $y, @ys ) = @{ $_[1] }; $x < $y ? [ $x, @{ merge( \@xs, [ $y, @ys ] ) } ] : [ $y, @{ merge( [ $x, @xs ], \@ys ) } ] } sub cancel; sub cancel{ return @_ unless @{ $_[0] } and @{ $_[1] }; my( $x, @xs ) = @{ $_[0] }; my( $y, @ys ) = @{ $_[1] }; return cancel \@xs, \@ys if $x == $y; return do{ my( $xs_, $ys_ ) = cancel \@xs, $_[1]; [$x, @{$xs_}], $ys_ }if $x < $y; return do{ my( $xs_,$ys_ ) = cancel $_[0], \@ys; $xs_, [$y, @{$ys_}] }; } package main; sub Scientific{ sprintf '%.17f', $_[0][0] / $_[0][1] } print Scientific FET::pCutoff [ 5, 0], [1, 4]; #print Scientific FET::pCutoff [ 989, 9400 ], [ 43300, 2400];