"Rheilly Phoull" wrote in message news: snipped-for-privacy@individual.net...
Hi.
I have appended a very handy Perl script I wrote to deal with not knowing all (or having forgot some) of the 1% values. It also finds pairs of values to get closer values than the standard spreads allow. (This is useful when using 0.1% parts)
Run it without arguments for invocation tips. Get Perl at
--
--Larry Brasfield email: donotspam_larry snipped-for-privacy@hotmail.com Above views may belong only to me.
============== script only follows ================ #!/usr/bin/perl
my $usage = '20%', 12 => '10%', 24 => '5%', 96 => '1%', ); my %digits = ( 3 => 2, 6 => 2, 12 => 2, 24 => 2, 96 => 3 );
# Unfortunately, the lower tolerances do not derive mathematically. %fudge2digits = ( '1.0' => '1.0', '1.1' => '1.1', '1.2' => '1.2', '1.3' => '1.3', '1.5' => '1.5', '1.6' => '1.6', '1.8' => '1.8', '2.0' => '2.0', '2.2' => '2.2', '2.4' => '2.4', '2.6' => '2.7', '2.9' => '3.0', '3.2' => '3.3', '3.5' => '3.6', '3.8' => '3.9', '4.2' => '4.3', '4.6' => '4.7', '5.1' => '5.1', '5.6' => '5.6', '6.2' => '6.2', '6.8' => '6.8', '7.5' => '7.5', '8.3' => '8.2', '9.1' => '9.1', );
my %stdtols;
map { my $tol = $stdsplits{$_}; $stdtols{$tol} = $_; } keys %stdsplits;
my $decsplit; my $tolerance; my $sigdigits;
sub saydec { print "Standard decade splits are: ", join(' ', sort keys %stdsplits), "\n"; } sub saytol { print "Standard tolerances are: ", join(' ', sort keys %stdtols), "\n"; }
if (!$pick) { print $usage; &saytol; &saydec; exit 1; }
if ($pick =~ m/^\d+$/) { if ($decsplit = $stdtols{$pick.'%'}) { $tolerance = $pick.'%'; } else { print $usage; &saytol; exit 1; } } elsif ($pick eq '-n' && ($tolerance = $stdsplits{$pick = shift})) { print "Standard $tolerance values:\n"; $decsplit = $pick; } else { print $usage; &saydec; exit 1; }
my $target = shift; my $parts = shift; my $combine = undef; if (! $parts) { $parts = 1; } else { unless ($parts =~ s/([apr])$/$combine=$1,''/e) { print $usage; print "Specify 2a, 2p or 2r as a combination method.\n"; exit 1; } }
$sigdigits = $digits{0+$decsplit};
my @values = ();
my $loginc = log(10) / $decsplit; my $fmt = sprintf("%%%1d.%1df", $sigdigits+1, $sigdigits-1); for (my $i = 0; $i < $decsplit; ++$i) { my $value = sprintf($fmt, exp($i * $loginc)); if ($sigdigits < 3) { $value = $fudge2digits{$value}; } if (! $target) { my $sep = (($i+1) % 12)? " " : "\n"; print "$value$sep"; } else { push(@values, $value + 0.0); } }
exit 0 unless $target;
push(@values, 10.0);
my %multsuf = ( 'f' => 1e-15, 'p' => 1e-12, 'n' => 1e-9, 'u' => 1e-6, 'm' => 1e-3, 'k' => 1e3, 'K' => 1e3, 'M' => 1e6, 'G' => 1e9, 'T' => 1e12, );
sub floor { my $v = shift; if ($v >= 0) { return int($v); } else { return -1 - int(-$v); } }
sub unsuffix { my $tv = shift; my $mult = 1; my $suf; if ($tv =~ s/([kKnupfmMGT])$/$suf=$1,''/e) { $mult = $multsuf{$suf}; } else { $suf = ''; } return $tv * $mult; }
sub closest { my $tv = shift; $tv = &unsuffix($tv); if ($tv = $lo && $findv < $hi) { my $gm = sqrt($lo * $hi); $bestv = ($findv < $gm)? $lo : $hi; last; } } return $bestv *= $prescale; }
if ($parts == 1) { print &closest($target), "\n"; }
sub gapprox { my ($tv, $scale, $rtvbase, $rtvadj) = @_; my $vb = &closest($scale * $tv); my $va = 1.0/$tv - 1.0/$vb; if ($va > 0) { $va = &closest(1.0/$va); $$rtvbase = $vb; $$rtvadj = $va; return 1.0/(1.0/$vb + 1.0/$va); } else { $$rtvbase = $vb; $$rtvadj = undef; return $vb; } }
sub zapprox { my ($tv, $scale, $rtvbase, $rtvadj) = @_; $$rtvbase = &closest($scale * $tv); my $va = $tv - $$rtvbase; if ($va > 0) { $$rtvadj = &closest($va); return $$rtvbase + $$rtvadj; } else { $$rtvadj = 0; return $$rtvbase; } }
sub rapprox { my ($rv, $scale, $rtvbase, $rtvadj) = @_; $$rtvbase = &closest($scale * $rv); $$rtvadj = &closest($$rtvbase / $rv); return $$rtvbase / $$rtvadj; }
if ($parts == 2) { my $tv = &unsuffix($target); if ($combine eq 'p') { my ($tvbase, $tvadj); my $bestratio = 2.0; my $bestgot = undef; my $bestscale = undef; for (my $scale = 1.00; $scale < 1.5; $scale += 0.01) { my ($tvb, $tva); my $tvgot = &gapprox($tv, $scale, \$tvb, \$tva); next unless $tvgot; my $ratio = $tvgot / $tv; if ($ratio < 1) { $ratio = 1.0 / $ratio; } if ($ratio < $bestratio) { $tvbase = $tvb; $tvadj = $tva; $bestratio = $ratio; $bestgot = $tvgot; } } my $adjv = defined($tvadj)? sprintf("%g",$tvadj) : 'none'; printf("Approximate %g as 1(1/%g + 1/%s), yielding %g (ratio = %6.4f)\n", $tv, $tvbase, $adjv, $bestgot, $bestratio); } if ($combine eq 'a') { my ($tvbase, $tvadj); my $bestratio = 2.0; my $bestgot = undef; my $bestscale = undef; for (my $scale = 1.0; $scale > 0.7; $scale -= 0.01) { my ($tvb, $tva); my $tvgot = &zapprox($tv, $scale, \$tvb, \$tva); my $ratio = $tvgot / $tv; if ($ratio < 1) { $ratio = 1.0 / $ratio; } if ($ratio < $bestratio) { $tvbase = $tvb; $tvadj = $tva; $bestratio = $ratio; $bestgot = $tvgot; } } printf("Approximate %g with (%g + %g), yielding %g (ratio = %6.4f)\n", $tv, $tvbase, $tvadj, $bestgot, $bestratio); } if ($combine eq 'r') { my ($tvbase, $tvadj); my $bestratio = 2.0; my $bestgot = undef; my $bestscale = undef; for (my $scale = 0.34; $scale < 3.4; $scale += 0.01) { my ($tvb, $tva); my $tvgot = &rapprox($tv, $scale, \$tvb, \$tva); my $ratio = $tvgot / $tv; if ($ratio < 1) { $ratio = 1.0 / $ratio; } if ($ratio < $bestratio) { $tvbase = $tvb; $tvadj = $tva; $bestratio = $ratio; $bestgot = $tvgot; } } printf("Approximate ratio %8.6f with (%g / %g), yielding %g\n", $tv, $tvbase, $tvadj, $bestgot); } } if ($parts > 2) { print "Sorry, not doing more than 2 parts yet.\n"; }
__END__