• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

briandfoy / PerlPowerTools / 12392947411

18 Dec 2024 12:30PM UTC coverage: 72.464% (-0.7%) from 73.196%
12392947411

Pull #884

github

Pull Request #884: perlpowertools: add hexdump tool

350 of 483 relevant lines covered (72.46%)

23489.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.91
/bin/units
1
#!/usr/bin/perl
2
package PerlPowerTools::units;
3

4
use strict;
5✔
5
use warnings;
5✔
6
use open qw(:std :utf8);
5✔
7

8
=begin metadata
9

10
Name: units
11
Description: conversion program
12
Author: Mark-Jason Dominus, mjd-perl-units@plover.com
13
License: gpl
14

15
=end metadata
16

17
=cut
18

19
use Config;
5✔
20

21
# Usage:
22
# units [-f unittab]
23
our $VERSION = '1.02';
24

25
BEGIN {
26
    require Data::Dumper;
5✔
27
        sub dumper { Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Useqq(1)->Deparse(1)->Dump }
164,225✔
28

29
        foreach my $letter ( qw( d p o l t ) ) {
5✔
30
          no strict 'refs';
5✔
31
          my $env_var = uc( "UNITS_DEBUG_$letter" );
25✔
32
          my( $debugging ) = grep { defined and length } ( $ENV{$env_var}, $ENV{UNITS_DEBUG}, 0 );
25✔
33
          *{"debug_$letter"} = ! $debugging ? sub {} : sub {
25✔
34
                my $indent;
×
35
                my $m = join '', @_;
×
36
                $indent = $1 if $m =~ s/\A(\s*)//;
×
37
                print "$indent$letter>>> $m\n";
×
38
          }
39
        }
25✔
40
}
41

42
our %unittab;            # Definitions loaded here
43

44
# Metric prefixes.  These must be powers of ten or change the
45
# token_value subroutine
46
our %PREF;
47
our $PREF;
48
our $PARSE_ERROR;
49

50
BEGIN {
51
  %PREF = (
5✔
52
    yotta => -24,
53
    zetta => -21,
54
    atto  => -18,
55
    femto => -15,
56
    pico  => -12,
57
    nano  => - 9,
58
    micro => - 6,
59
    milli => - 3,
60
    centi => - 2,
61
    deci  => - 1,
62
    deca  =>   1,
63
    deka  =>   1,
64
    hecto =>   2,
65
    hect  =>   2,
66
    kilo  =>   3,
67
    myria =>   4,
68
    mega  =>   6,
69
    giga  =>   9,
70
    tera  =>  12,
71
    zepto =>  15,
72
    yocto =>  18,
73
  );
74
  $PREF = join '|', sort {$PREF{$a} <=> $PREF{$b}} (keys %PREF);
5✔
75
}
76

77
# run if called directly, indirectly, directly par-packed, undirectly par-packed
78
__PACKAGE__->run(@ARGV) if !caller() || caller(0) =~ /^(PerlPowerTools::Packed|PAR)$/ || caller(1) eq 'PAR'; # modulino
79

80
sub run {
81
  my( $class, @args ) = @_; local @ARGV;
×
82

83
  my $args = $class->process_args( @args );
×
84

85
  $class->read_unittab( $args->{unittabs}[0] );
×
86

87
  if (@{ $args->{args} }) {
×
88
    my ($have, $want) = @{ $args->{args} };
×
89
    my $have_hr = $class->unit_have($have);
×
90
    my $want_hr = $class->unit_want($want);
×
91
    my %r = $class->unit_convert($have_hr, $want_hr);
×
92
    print_result(%r);
×
93
  } else {
94
    while (1) {
×
95
      print "You have: ";
×
96
      my $have = <>;
×
97
      exit 0 unless defined($have) && $have =~ /\S/;
×
98
      my $have_hr = $class->unit_have($have);
×
99
      next if is_Zero($have_hr->{hu});
×
100

101
      print "You want: ";
×
102
      my $want = <>;
×
103
      exit 0 unless defined($want) && $want =~ /\S/;
×
104
      my $want_hr = $class->unit_want($want);
×
105
      next if is_Zero($want_hr->{wu});
×
106

107
      my %r = $class->unit_convert($have_hr, $want_hr);
×
108
      print_result(%r);
×
109
    }
110
  }
111

112
  exit 0;
×
113
}
114

115
sub test {
116
    my ($class, $have, $want) = @_;
100✔
117

118
    $class->read_unittab();
100✔
119
    my $have_hr = $class->unit_have($have);
100✔
120
    my $want_hr = $class->unit_want($want);
100✔
121
    my %r = $class->unit_convert($have_hr, $want_hr);
100✔
122
    return %r;
100✔
123
}
124

125
sub default_unittabs {
126
  grep { -e } qw(/usr/lib/unittab);
×
127
}
128

129
sub env_unittabs {
130
  no warnings 'uninitialized';
5✔
131
  split /$Config{path_sep}/, $ENV{UNITTAB};
×
132
}
133

134
sub process_args {
135
    my( $class, @args ) = @_;
×
136

137
    my @unittabs;
×
138
    while (@args and $args[0] =~ /^-/) {
×
139
      my $flag = shift @args;
×
140
      if ($flag =~ s/\A\-f//) {
×
141
        my $file = $flag;
×
142
        $file = shift @args if (length($file) == 0);
×
143
        $class->usage() unless defined $file;
×
144
        push @unittabs, $file;
×
145
      } elsif ($flag eq '--') {
146
        last;
×
147
      } elsif ($flag =~ /^--version$/) {
148
        print "perl units version $VERSION.\n";
×
149
        exit 0;
×
150
      } else {
151
        warn "Unknown flag: $flag.\n";
×
152
        $class->usage();
×
153
      }
154
    }
155

156
    $class->usage() if @args == 1 || @args > 2;
×
157

158
    @unittabs = $class->env_unittabs unless @unittabs;
×
159
    @unittabs = $class->default_unittabs unless @unittabs;
×
160

161
    { unittabs => \@unittabs, args => \@args }
×
162
}
163

164
sub read_unittab {
165
  my( $class, $file ) = @_;
100✔
166

167
  my $fh;
100✔
168
  if (defined $file) {
100✔
169
    unless (-d $file) {
×
170
      open $fh, '<:encoding(UTF-8)', $file or do {
×
171
        die "Could not open <$file>: $!\n";
×
172
      };
173
      $class->read_defs($file, $fh);
×
174
      return;
×
175
    }
176
  }
177
  debug_d('Reading from DATA');
100✔
178
  open $fh, '<:encoding(UTF-8)', __FILE__ or die;
5✔
179
  while (<$fh>) {
100✔
180
    last if /\A__(?:DATA|END)__/;
94,900✔
181
  }
182
  $class->read_defs('DATA', $fh);
100✔
183
}
184

185
sub unit_have {
186
  my ($class, $have) = @_;
100✔
187

188
  trim($have);
100✔
189

190
  my $is_negative = 0;
100✔
191
  if ($have =~ /^[-]/) {
100✔
192
    $is_negative = 1;
10✔
193
    $have =~ s/^[-]//;  # remove minus sign
10✔
194
  }
195

196
  my $is_quantified = $have =~ /^[\d.]+/;
100✔
197

198
  if ($have =~ s/^\s*\#\s*//) {
100✔
199
    if ($class->definition_line($have)) {
×
200
      print "Defined.\n";
×
201
    } else {
202
      print "Error: $PARSE_ERROR.\n";
×
203
    }
204
    return;
×
205
  }
206
  return unless $have =~ /\S/;
100✔
207

208
  my $hu = $class->parse_unit($have);
100✔
209

210
  if (is_Zero($hu)) {
100✔
211
    print $PARSE_ERROR, "\n";
×
212
    return;
×
213
  }
214

215
  return { have => $have, hu => $hu, neg => $is_negative, quan => $is_quantified };
100✔
216
}
217

218
sub unit_want {
219
    my ($class, $want) = @_;
100✔
220

221
    trim($want);
100✔
222
    return unless $want =~ /\S/;
100✔
223

224
    my $wu = $class->parse_unit($want);
100✔
225

226
    if (is_Zero($wu)) {
100✔
227
      print $PARSE_ERROR, "\n";
×
228
    }
229
    return { want => $want, wu => $wu };
100✔
230
}
231

232
sub unit_convert {
233
    my ($class, $have_hr, $want_hr ) = @_;
100✔
234

235
    my $have = $have_hr->{have};
100✔
236
    my $hu = $have_hr->{hu};
100✔
237
    my $is_negative = $have_hr->{neg};
100✔
238
    my $is_quantified = $have_hr->{quan};
100✔
239

240
    my $want = $want_hr->{want};
100✔
241
    my $wu = $want_hr->{wu};
100✔
242

243
    debug_t('have unit', dumper($hu));
100✔
244
    debug_t('want unit', dumper($wu));
100✔
245

246
    my $is_temperature = 0;
100✔
247
    $is_temperature++ if $hu->{Temperature};
100✔
248
    $is_temperature++ if $wu->{Temperature};
100✔
249

250
    my $quot
100✔
251
        = $is_temperature == 2
252
        ? undef
253
        : unit_divide($hu, $wu);
254

255
    my %retval;
100✔
256

257
    if ($is_temperature == 2) {
100✔
258
        # we have temperature units
259
        $have =~ s/^[-]?[\d.]*\s*//;
65✔
260
        my $v = $hu->{'_'};
65✔
261
        $v *= -1 if $is_negative;
65✔
262
        $v  =  0 if not $is_quantified;
65✔
263
        my $k
264
            = exists $hu->{hof}
265
            ? $hu->{hof}->{to}->($v)
65✔
266
            : $v;
267
        my $t
268
            = exists $wu->{hof}
269
            ? $wu->{hof}->{from}->($k)
65✔
270
            : $k;
271
        %retval = ( type => 'temperature', v => $v, have => $have, t => $t, want => $want );
65✔
272
    }
273
    elsif (is_dimensionless($quot)) {
274
      my $q = $quot->{_};
35✔
275
      my $p = 1/$q;
35✔
276
      %retval = ( type => 'dimless', q => $q, p => $p);
35✔
277
    }
278
    else {
279
      %retval = ( type=> 'error', msg =>
×
280
        "conformability (Not the same dimension)\n" .
281
        "\t" . $have . " is " . text_unit($hu) . "\n" .
282
        "\t" . $want . " is " . text_unit($wu) . "\n"
283
        );
284
    }
285

286
    return %retval;
100✔
287
}
288

289
sub print_result {
290
    my (%r) = @_;
×
291
    printf "\t%.6g %s is %.6g %s\n", $r{v}, $r{have}, $r{t}, $r{want}
292
        if $r{type} eq 'temperature';
×
293
    printf "\t* %.6g\n\t/ %.6g\n", $r{q}, $r{p}
294
        if $r{type} eq 'dimless';
×
295
    print $r{msg} if $r{type} eq 'error';
×
296
}
297

298
################################################################
299

300
sub usage {
301
  my( $class ) = @_;
×
302
  require Pod::Usage;
×
303
  Pod::Usage::pod2usage({ -exitval => 1, -verbose => 0 });
×
304
}
305

306
sub read_defs {
307
  my ($class, $filename, $fh) = @_;
100✔
308
  while (<$fh>) {
100✔
309
          next if m|\A/|;  # comment line
42,100✔
310
    trim($_);
42,000✔
311
    next unless /\S/;
42,000✔
312

313
    debug_d( "$_" );
35,300✔
314
    my $hash = $class->definition_line($_);
35,300✔
315
    foreach my $key ( keys %$hash ) {
35,300✔
316
      $unittab{$key} = $hash->{$key};
35,300✔
317
    }
318
  }
319
}
320

321
sub definition_line {
322
  my ($class, $line) = @_;
35,300✔
323
  my ($name, $data) = split /\s+/, $line, 2;
35,300✔
324
  my $value = $class->parse_unit($data);
35,300✔
325
  debug_t("$name => $data") if $data =~ /^\{\s/;
35,300✔
326
  my $rc = do {
35,300✔
327
    if ($data =~ /^\{\s/) {
35,300✔
328
        my $hof = eval $data;   # hash of functions
300✔
329
        +{ $name => { _ => 1, hof => $hof, Temperature => 1 } }
300✔
330
    }
331
    elsif (is_Zero($value))        { undef                              }
×
332
    elsif (is_fundamental($value)) { +{ $name => {_ => 1, $name => 1} } }
900✔
333
    else                           { +{ $name => $value               } }
34,100✔
334
  };
335

336
  unless( defined $rc ) {
35,300✔
337
    $line =~ s/\s+/ => /;
×
338
    warn "Parse error: $PARSE_ERROR in $line.  Skipping.\n";
×
339
    $rc = {};
×
340
  }
341

342
  return $rc;
35,300✔
343
}
344

345
sub trim {              # note that trim() is a L-value sub
346
  $_[0] =~ s/\#.*$//;;
42,200✔
347
  $_[0] =~ s/\s+$//;
42,200✔
348
  $_[0] =~ s/^\s+//;
42,200✔
349
}
350

351
sub Zero () { +{ _ => 0 } }
600✔
352

353
# here we guard the zero test by first checking to see
354
# if we're dealing with a temperature
355
sub is_Zero { !$_[0]{Temperature} && !$_[0]{_} }
35,200✔
356

357
sub unit_lookup {
358
  my ($name) = @_;
48,010✔
359
  debug_l( "Looking up unit '$name'" );
48,010✔
360
  return $unittab{$name} if exists $unittab{$name};
48,010✔
361
  if ($name =~ /s$/) {
2,520✔
362
    my $shortname = $name;
20✔
363
    $shortname =~ s/s$//;
20✔
364
    return $unittab{$shortname} if exists $unittab{$shortname};
20✔
365
  }
366
  my ($prefix, $rest) = ($name =~ /^($PREF-?)(.*)/o);
2,500✔
367
  unless ($prefix) {
2,500✔
368
    $PARSE_ERROR = "Unknown unit '$name'";
300✔
369
    return Zero;
300✔
370
  }
371
  my $base_unit = unit_lookup($rest); # Recursive
2,200✔
372
  con_multiply($base_unit, 10**$PREF{$prefix});
2,200✔
373
}
374

375
sub unit_multiply {
376
  my ($a, $b) = @_;
25,320✔
377
  debug_o( "Multiplying @{[%$a]} by @{[%$b]}: " );
25,320✔
378
  my $r = {%$a};
25,320✔
379
  $r->{_} *= $b->{_};
25,320✔
380
  for my $u (keys %$b) {
25,320✔
381
    next if $u eq '_';
33,220✔
382
    $r->{$u} += $b->{$u};
7,900✔
383
  }
384
  debug_o( "\tResult: @{[%$r]}" );
25,320✔
385
  $r;
25,320✔
386
}
387

388
sub unit_divide {
389
  my ($a, $b) = @_;
6,945✔
390
  my $r = {%$a};
6,945✔
391
  die "Division by zero error" if $b->{_} == 0;
6,945✔
392
  $r->{_} /= $b->{_};
6,945✔
393
  for my $u (keys %$b) {
6,945✔
394
    next if $u eq '_';
14,495✔
395
    $r->{$u} -= $b->{$u};
7,550✔
396
  }
397
  $r;
6,945✔
398
}
399

400
sub unit_power {
401
  my ($p, $u) = @_;
7,405✔
402
  debug_o( "Raising unit @{[%$u]} to power $p." );
7,405✔
403
  my $r = {%$u};
7,405✔
404
  $r->{_} **= $p;
7,405✔
405
  for my $d (keys %$r) {
7,405✔
406
    next if $d eq '_';
14,910✔
407
    $r->{$d} *= $p;
7,505✔
408
  }
409
  debug_o( "\tResult: @{[%$r]}" );
7,405✔
410
  $r;
7,405✔
411
}
412

413
sub unit_dimensionless {
414
  debug_o( "Turning $_[0] into a dimensionless unit." );
21,020✔
415
  return +{_ => $_[0]};
21,020✔
416
}
417

418
sub con_multiply {
419
  my ($u, $c) = @_;
2,420✔
420
  debug_o( "Multiplying unit @{[%$u]} by constant $c." );
2,420✔
421
  my $r = {%$u};
2,420✔
422
  $r->{_} *= $c;
2,420✔
423
  debug_o( "\tResult: @{[%$r]}" );
2,420✔
424
  $r;
2,420✔
425
}
426

427
sub is_dimensionless {
428
  my ($r) = @_;
35✔
429
  for my $u (keys %$r) {
35✔
430
    next if $u eq '_';
75✔
431
    return if $r->{$u} != 0;
40✔
432
  }
433
  return 1;
35✔
434
}
435

436
# Generate bogus unit value that signals that a new fundamental unit
437
# is being defined
438
sub new_fundamental_unit {
439
  return +{__ => 'new', _ => 1};
900✔
440
}
441

442
# Recognize this bogus value when it appears again.
443
sub is_fundamental {
444
  exists $_[0]{__};
35,000✔
445
}
446

447
sub text_unit {
448
  my ($u) = @_;
×
449
  my (@pos, @neg);
×
450
  my $c = $u->{_};
×
451
  for my $k (sort keys %$u) {
×
452
    next if $k eq '_' or $k eq 'hof';
×
453
    push @pos, $k if $u->{$k} > 0;
×
454
    push @neg, $k if $u->{$k} < 0;
×
455
  }
456
  my $text = ($c == 1 ? '' : $c);
×
457
  for my $d (@pos) {
×
458
    my $e = $u->{$d};
×
459
    $text .= " $d";
×
460
    $text .= "^$e" if $e > 1;
×
461
  }
462

463
  $text .= ' per' if @neg;
×
464
  for my $d (@neg) {
×
465
    my $e = - $u->{$d};
×
466
    $text .= " $d";
×
467
    $text .= "^$e" if $e > 1;
×
468
  }
469

470
  $text;
×
471
}
472
################################################################
473
#
474
# I'm the parser
475
#
476

477
our @actions;
478
BEGIN {
479
  sub sh { ['shift', $_[0]]  };
240✔
480
  sub go { ['goto', $_[0]] };
65✔
481

482
  my $eof_state = 98;
5✔
483

484
  @actions =
485
    (
486
     # Initial state
487
     {
488
     PREFIX      => sh(1),
489
     NUMBER      => sh(2),
490
     NAME        => sh(3),
491
     FUNDAMENTAL => sh(4),
492
     FRACTION    => sh(5),
493
     POWER       => sh(17),
494
     '('         => sh(6),
495
     'unit'      => go(7),
496
     'topunit'   => go($eof_state),
497
     'constant'  => go(8),
498
     },
499

500
     # State 1:   constant -> PREFIX .
501
     { _ => ['reduce', 1, 'constant']},
502

503
     # State 2:   constant -> NUMBER .
504
     { _ => ['reduce', 1, 'constant']},
505

506
     # State 3:   unit -> NAME .
507
     { _ => ['reduce', 1, 'unit', \&unit_lookup ]},
508

509
     # State 4:   unit -> FUNDAMENTAL .
510
     { _ => ['reduce', 1, 'unit', \&new_fundamental_unit ]},
511

512
     # State 5:   constant -> FRACTION .
513
     { _ => ['reduce', 1, 'constant']},
514

515
     # State 6:   unit -> '(' . unit ')'
516
     {PREFIX      => sh(1),
517
      NUMBER      => sh(2),
518
      NAME        => sh(3),
519
      FUNDAMENTAL => sh(4),
520
      FRACTION    => sh(5),
521
      '('         => sh(6),
522
      'unit'      => go(9),
523
      'constant'  => go(8),
524
     },
525

526
     # State 7:   topunit -> unit .
527
     #            unit  ->  unit . TIMES unit
528
     #            unit  ->  unit . DIVIDE unit
529
     #            unit  ->  unit . NUMBER
530
     {NUMBER => sh(10),
531
      TIMES  => sh(11),
532
      DIVIDE => sh(12),
533
      POWER  => sh(17),
534
      _      =>  ['reduce', 1, 'topunit'],
535
     },
536

537
     # State 8:   unit -> constant . unit
538
     #            unit -> constant .
539
     {PREFIX      => sh(1),
540
      NUMBER      => sh(2), # Shift-reduce conflict resolved in favor of shift
541
      NAME        => sh(3),
542
      FUNDAMENTAL => sh(4),
543
      FRACTION    => sh(5),
544
      '('         => sh(6),
545
      _           => ['reduce', 1, 'unit', \&unit_dimensionless],
546
      'unit'      => go(13),
547
      'constant'  => go(8),
548
     },
549

550
     # State 9:   unit -> unit . TIMES unit
551
     #            unit -> unit . DIVIDE unit
552
     #            unit -> '(' unit . ')'
553
     #            unit -> unit . NUMBER
554
     {NUMBER => sh(10),
555
      TIMES  => sh(11),
556
      DIVIDE => sh(12),
557
      POWER  => sh(17),
558
      ')'    => sh(14),
559
     },
560

561
     # State 10:  unit -> unit NUMBER .
562
     { _ => ['reduce', 2, 'unit',
563
         sub {
564
           unless (int($_[1]) == $_[1]) {
7,405✔
565
             ABORT("Nonintegral power $_[1]");
×
566
             return Zero;
×
567
           }
568
           unit_power(@_);
7,405✔
569
         }
570
        ],
571
     },
572

573
     # State 11:  unit -> unit TIMES . unit
574
     {PREFIX      => sh(1),
575
      NUMBER      => sh(2),
576
      NAME        => sh(3),
577
      FUNDAMENTAL => sh(4),
578
      FRACTION    => sh(5),
579
      '('         => sh(6),
580
      'unit'      => go(15),
581
      'constant'  => go(8),
582
     },
583

584
     # State 12:  unit -> unit DIVIDE . unit
585
     {PREFIX      => sh(1),
586
      NUMBER      => sh(2),
587
      NAME        => sh(3),
588
      FUNDAMENTAL => sh(4),
589
      FRACTION    => sh(5),
590
      '('         => sh(6),
591
      'unit'      => go(16),
592
      'constant'  => go(8),
593
     },
594

595
     # State 13:  unit -> unit . TIMES unit
596
     #            unit -> unit . DIVIDE unit
597
     #            unit -> constant unit .
598
     #            unit -> unit . NUMBER
599
     {NUMBER => sh(10),  # Shift-reduce conflict resolved in favor of shift
600
      TIMES  => sh(11),  # Shift-reduce conflict resolved in favor of shift
601
      DIVIDE => sh(12),  # Shift-reduce conflict resolved in favor of shift
602
      POWER  => sh(17),
603
      _      => ['reduce', 2, 'unit', \&con_multiply],
604
     },
605

606
     # State 14: unit => '(' unit ')' .
607
     { _ => ['reduce', 3, 'unit', sub {$_[1]}] },
×
608

609
     # State 15: unit  ->  unit . TIMES unit
610
     #           unit  ->  unit TIMES unit .
611
     #           unit  ->  unit . DIVIDE unit
612
     #           unit  ->  unit . NUMBER
613
     {NUMBER => sh(10), # Shift-reduce conflict resolved in favor of shift
614
      _ => ['reduce', 3, 'unit', sub {unit_multiply($_[0], $_[2])}],
25,320✔
615
     },
616

617
     # State 16: unit  ->  unit . TIMES unit
618
     #           unit  ->  unit DIVIDE unit .
619
     #           unit  ->  unit . DIVIDE unit
620
     #           unit  ->  unit . NUMBER
621
     {NUMBER => sh(10), # Shift-reduce conflict resolved in favor of shift
622
      _ => ['reduce', 3, 'unit', sub{unit_divide($_[2], $_[0])}],
6,910✔
623
     },
624

625
     # State 17:  unit -> unit POWER . unit
626
     {
627
      NUMBER      => sh(2),
628
      'constant'  => go(18),
629
     },
630

631
     # State 18: unit -> unit POWER
632
     {
633
     NUMBER => sh(2),
634
     _ => ['reduce', 3, 'unit', sub{ unit_power($_[0], $_[2])}],
5✔
635
     },
636

637
    );
638

639
    $actions[98] = {EOF => go($eof_state + 1),};
5✔
640
    $actions[99] = {_   => ['accept']};
5✔
641
}
642

643
sub ABORT {
644
  $PARSE_ERROR = shift;
×
645
}
646

647
sub parse_unit {
648
  my ($class, $s) = @_;
35,500✔
649
  my $tokens = lex($s);
35,500✔
650
  my $STATE = 0;
35,500✔
651
  my (@state_st, @val_st);
35,500✔
652

653
  $PARSE_ERROR = undef;
35,500✔
654

655
  debug_p(  '-' x 50 . "\n" );
35,500✔
656
  # Now let's run the parser
657
  for (;;) {
35,500✔
658
    return Zero if $PARSE_ERROR;
342,310✔
659

660
    debug_p( "Tokens: " . join( ' ', map { "<$_>" } @$tokens ) );
342,010✔
661
    my $la = @$tokens ? token_type($tokens->[0]) : 'EOF';
342,010✔
662
    debug_p( "Now in state $STATE.  Lookahead type is $la." );
342,010✔
663
    debug_p( "State stack is (@state_st)." );
342,010✔
664
    my $actiontab = $actions[$STATE];
342,010✔
665
    my $action = $actiontab->{$la} || $actiontab->{_};
342,010✔
666
    unless ($action) {
342,010✔
667
      $PARSE_ERROR = 'Syntax error';
×
668
      return Zero;
×
669
    }
670

671
    my ($primary, @actargs) = @$action;
342,010✔
672
    debug_p( "Next thing: $primary (@actargs)" );
342,010✔
673
    if ($primary eq 'accept') {
342,010✔
674
      return $val_st[0];    # Success!
35,200✔
675
    } elsif ($primary eq 'shift') {
676
      my $token = shift @$tokens;
107,585✔
677
      my $val = token_value($token);
107,585✔
678
      debug_p( "shift: token: <$token> val: <$val>" );
107,585✔
679
      push @val_st, $val;
107,585✔
680
      push @state_st, $STATE;
107,585✔
681
      $STATE = $actargs[0];
107,585✔
682
      debug_p( "shift: state: <$STATE>" );
107,585✔
683
    } elsif ($primary eq 'goto') {
684
      $STATE = $actargs[0];
35,200✔
685
    } elsif ($primary eq 'reduce') {
686
      my ($n_args, $result_type, $semantic) = @actargs;
164,025✔
687
      my @arglist;
164,025✔
688
      while ($n_args--) {
164,025✔
689
        push @arglist, pop @val_st;
236,110✔
690
        $STATE = pop @state_st;
236,110✔
691
      }
692
      my $result = $semantic ? &$semantic(@arglist) : $arglist[0];
164,025✔
693
      push @val_st, $result;
164,025✔
694
      push @state_st, $STATE;
164,025✔
695
    debug_p( "reduce: Value stack is " . dumper( \@val_st ) );
164,025✔
696

697
      debug_p( "Post-reduction state is $STATE." );
164,025✔
698

699
      # Now look for 'goto' actions
700
      my $goto = $actions[$STATE]{$result_type};
164,025✔
701
      unless ($goto && $goto->[0] eq 'goto') {
164,025✔
702
        die "No post-reduction goto in state $STATE for $result_type.\n";
×
703
      }
704
      debug_p( "goto $goto->[1]" );
164,025✔
705
      $STATE = $goto->[1];
164,025✔
706
    } else {
707
      die "Bad primary $primary";
×
708
    }
709
  }
710
}
711

712

713
sub lex {
714
  my ($s) = @_;
35,500✔
715
  my $N = '(?:\d+\.\d+|\d+|\.\d+)(?:[eE][-+]?\d+)?';
35,500✔
716

717
  my @t = split /(
35,500✔
718
                   (?: \*.\* | !.! ) # Special 'new unit' symbol
719
                |  [()*-]                    # Symbol
720
                |  \s*(?:\/|\bper\b)\s*      # Division
721
                |  (?:$N\|$N)                # Fraction
722
                |  $N                        # Decimal number
723
                |  \d+                       # Integer
724
                |  [A-Za-z_][A-Za-z_.]*      # identifier
725
                |  \s+                       # White space
726
                )/ox, $s;
727
  @t = grep {defined and $_ ne ''} @t;  # Discard empty and all-white tokens
35,500✔
728
  debug_p( "Input: $s Tokens: @t" );
35,500✔
729
  \@t;
35,500✔
730
}
731

732
sub token_type {
733
  my ($token) = @_;
175,560✔
734
  return $token->[0]   if ref $token;
175,560✔
735
  return $token        if $token =~ /[()]/;
175,560✔
736
  return 'TIMES'       if $token =~ /^\s+$/;
175,560✔
737
  return 'FUNDAMENTAL' if $token =~ m/\A(!.!|\*.\*)\z/;
112,600✔
738
  return 'DIVIDE'      if $token =~ /^\s*(\/|\bper\b)\s*$/;
111,700✔
739
  return 'TIMES'       if $token eq '*' || $token eq '-';
93,580✔
740
  return 'FRACTION'    if $token =~ /^\d+\|\d+$/;
82,080✔
741
  return 'NUMBER'      if $token =~ /^[.\d]/;
78,075✔
742
  return 'POWER'       if $token eq '^';
46,030✔
743
  return 'NAME';
46,030✔
744
}
745

746
sub token_value {
747
  my ($token) = @_;
107,585✔
748
  debug_p( "TOKEN VALUE: <$token>" );
107,585✔
749

750
  my $rc = do {
107,585✔
751
       if( $token =~ /^([()*\/-]|\s*\bper\b\s*)$/ ) { $token }
107,585✔
752
    elsif( $token =~ /(\d+)\|(\d+)/ ) {
753
      if( $2 == 0 ) {
4,205✔
754
        ABORT("Zero denominator in fraction '$token'");
×
755
        return 0;
×
756
      }
757
      $1/$2;
4,205✔
758
    }
759
    else { $token }
92,570✔
760
  };
761

762
  return $rc;        # Perl takes care of the others.
107,585✔
763
}
764

765
=encoding utf8
766

767
=head1 NAME
768

769
units - conversion program
770

771
=head1 SYNOPSIS
772

773
    % units
774
        You have: in
775
        You want: cm
776
                * 2.54
777
                / 0.393701
778

779
    % units [-f /path/to/unittab] [want_unit have_unit]
780

781
=head1 OPTIONS
782

783
    -f           Use specified definition file
784
    --version    Display version information
785

786
=head1 DESCRIPTION
787

788
NOTE: This does not handle the Gnu units format (https://www.gnu.org/software/units/).
789

790
The units program converts quantities expressed in various scales to their
791
equivalents in other scales.  The units program can only handle multiplicative
792
or affine scale changes (except for temperature).  It works in one of
793
two ways.  If given two units as command line arguments, it reports
794
the conversion.  Otherwise, it operates interactively by prompting the user
795
for inputs:
796

797
    % units
798
    You have: meters
799
    You want: feet
800
        * 3.2808399
801
        / 0.3048
802

803
    You have: cm3
804
    You want: gallons
805
        * 0.00026417205
806
        / 3785.4118
807

808
    You have: meters/s
809
    You want: furlongs/fortnight
810
        * 6012.8848
811
        / 0.00016630952
812

813
    You have: 1|2 inch
814
    You want: cm
815
        * 1.27
816
        / 0.78740157
817

818
    You have: 98.6 F
819
    You want: C
820
        98.6 F is 37 C
821

822
    You have: -40 C
823
    You want: F
824
        -40 C is -40 F
825

826
Powers of units can be specified using the '^' character as shown in the
827
example, or by simple concatenation: 'cm3' is equivalent to 'cm^3'.
828

829
Multiplication of units can be specified by using spaces, a dash or an asterisk.
830

831
Division of units is indicated by the slash ('/').  Note that multiplication has
832
a higher precedence than division, so 'm/s/s' is the same as 'm/s^2' or 'm/s s'.
833
Division of numbers must be indicated using the vertical bar ('|').  To convert
834
half a meter, you would write '1|2 meter'.  If you write '1/2 meter' then the
835
units program would interpret that as equivalent to '0.5/meter'.
836

837
If you enter incompatible unit types, the units program will print a message
838
indicating that the units are not conformable and it will display the reduced
839
form for each unit:
840

841
    You have: ergs/hour
842
    You want: fathoms kg^2 / day
843
    conformability error
844
         2.7777778e-11 kg m^2 / sec^3
845
         2.1166667e-05 kg^2 m / sec
846

847
The conversion information is read from a units data file.  The default file
848
includes definitions for most familiar units, abbreviations and metric
849
prefixes.  Some constants of nature included are:
850

851
    pi         ratio of circumference to diameter
852
    c          speed of light
853
    e          charge on an electron
854
    g          acceleration of gravity
855
    force      same as g
856
    mole       Avogadro's number
857
    water      pressure per unit height of water
858
    mercury    pressure per unit height of mercury
859
    au         astronomical unit
860

861
The unit 'pound' is a unit of mass.  Compound names are run together so 'pound
862
force' is a unit of force.  The unit 'ounce' is also a unit of mass.  The fluid
863
ounce is 'floz'.  British units that differ from their US counterparts are
864
prefixed with 'br', and currency is prefixed with its country name:
865
'belgiumfranc', 'britainpound'.  When searching for a unit, if the specified
866
string does not appear exactly as a unit name, then units will try to remove a
867
trailing 's' or a trailing 'es' and check again for a match.
868

869
To find out what units are available read the standard units file.  If you want
870
to add your own units you can supply your own file.  If no standard file
871
exists and you do not supply your own file, this program uses internal
872
data.
873

874
A unit is specified on a single line by giving its name and an equivalence.  Be
875
careful to define new units in terms of old ones so that reductions leads to
876
primitive units.  Primitive (a.k.a. fundamental) units are defined
877
with a string of three characters which begin and end with '*' or '!'.
878
Note that the units program will not detect infinite loops that could be
879
caused by careless unit definitions.
880

881
Comments in the unit definition file begin with a '/' or '#' character at
882
the beginning of a line.  Once the parser has successfully parsed a
883
unit name and it's definition, the remainder of the line is ignored.
884
This makes it safe to include in-line comments.
885

886
Prefixes are defined in the same way as standard units, but with a
887
trailing dash at the end of the prefix name.  If a unit is not found even
888
after removing trailing 's' or 'es', then it will be checked against the
889
list of prefixes.  Prefixes will be removed until a legal base unit is
890
identified.
891

892
Here is an example of a short units file that defines some basic units.
893

894
    m           !a!
895
    sec         ***
896
    Temperature ***
897
    micro-      1e-6
898
    minute      60 sec
899
    hour        60 min
900
    inch        0.0254 m
901
    ft          12 inches
902
    mile        5280 ft
903

904
If a "Temperature" dimension is defined in the units table, then
905
you can define various temperature scales as units by specifying
906
the code needed to convert the unit to or from Kelvin.
907
The built-in units table has definitions for Kelvin (K), Celsius (C),
908
Fahrenheit (F) and Rankine (R).
909

910
The code consists of a perl hash containing the keys 'to' and 'from'.
911
The values are the subroutine definitions necessary to convert a
912
value from Kelvin to the specified unit, or to Kelvin from the the
913
specified unit.  See the built-in unit table for examples.
914

915
A temperature unit entered at "You have" without any constant
916
preceding it will default to zero units.  This is in contrast to
917
non-temperature units, where a bare unit name is assumed to mean 1
918
unit.  Also, for temperatures only, negative constants are allowed.
919
This enables, for example, a conversation between -40C and F.
920

921
=head1 AUTHOR
922

923
Mark-Jason Dominus, C<< <mjd-perl-units@plover.com> >>
924

925
Temperature support by Gary Puckering, C<< <jgpuckering@rogers.com> >>
926

927
Currently maintained in https://github.com/briandfoy/PerlPowerTools
928

929
=head1 BUGS
930

931
=head1 COPYRIGHT and LICENSE
932

933
This program is copyright (c) M-J. Dominus (1996, 1999).
934

935
This program is free software; you can redistribute it and/or modify it under
936
the terms of the GNU General Public License as published by the Free Software
937
Foundation; either version 2 of the License, or (at your option) any later
938
version, or under Perl's 'Artistic License'.
939

940
This program is distributed in the hope that it will be useful, but WITHOUT ANY
941
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
942
PARTICULAR PURPOSE.  See the GNU General Public License for more details.
943

944
=cut
945

946
no warnings qw(void);
5✔
947
__PACKAGE__;
948

949
__END__
950

951
# Notes (from Gary Puckering)
952
#  1.  The comment indicator is "/" at the start of a line
953
#  2.  However, the parser ignores trailing unrecognized trailing tokens
954
#      and so # seems to be an effective in-line comment indicator
955
#  3.  Temperature entries in version 1.034 and prior caused parsing errors
956
#  4.  Temperature support has now been added, and the entries have been updated
957
#  5.  If you have your own units file and it has temperatures, you'll need to update it
958

959
# dimensions
960
m                     ***
961
kg                    ***
962
sec                   ***
963
coul                  ***
964
candela               ***
965
radian                ***
966
bit                   ***
967
erlang                ***
968
Temperature           ***
969

970
# constants
971

972
unity                 1
973
pi                    3.14159265358979323846 unity
974
c                     2.997925e+8 m/sec unity
975
g                     9.80665 m/sec2
976
au                    1.49597871e+11 m unity
977
mole                  6.022169e+23 unity
978
e                     1.6021917e-19 coul unity
979
energy                c2
980
force                 g
981
mercury               1.33322e+5 kg/m2-sec2
982
hg                    mercury
983

984
# dimensionless
985

986
degree                1|180 pi-radian
987
circle                2 pi-radian
988
turn                  2 pi-radian
989
grade                 .9 degree
990
arcdeg                1 degree
991
arcmin                1|60 arcdeg
992
ccs                   1|36 erlang
993
arcsec                1|60 arcmin
994

995
steradian             radian2
996
sphere                4 pi-steradian
997
sr                    steradian
998

999
# Time
1000

1001
second                sec
1002
s                     sec
1003
minute                60 sec
1004
min                   minute
1005
hour                  60 min
1006
hr                    hour
1007
day                   24 hr
1008
da                    day
1009
week                  7 day
1010
year                  365.24219879 day unity
1011
yr                    year
1012
month                 1|12 year
1013
ms                    millisec
1014
us                    microsec
1015

1016
# Mass
1017

1018
gram                  millikg
1019
gm                    gram
1020
mg                    milligram
1021
metricton             kilokg
1022

1023
# Temperature
1024
C                     { to => sub { $_[0] + 273.15 }, from => sub { $_[0] - 273.15 } }
1025
F                     { to => sub { ( $_[0] + 459.67 ) * 5/9 }, from => sub { $_[0] * 9/5 - 459.67 } }
1026
R                     { to => sub { $_[0] * 5/9 }, from => sub { $_[0] * 9/5 } }
1027
K                     Temperature
1028
Celsius               C
1029
Fahrenheit            F
1030
Kelvin                K
1031
Rankine               R
1032
celsius               C
1033
fahrenheit            F
1034
kelvin                K
1035
rankine               R
1036

1037
# Avoirdupois
1038

1039
lb                    .45359237 kg
1040
lbf                   lb g
1041
ounce                 1|16 lb
1042
oz                    ounce
1043
dram                  1|16 oz
1044
dr                    dram
1045
grain                 1|7000 lb
1046
gr                    grain
1047
shortton              2000 lb
1048
ton                   shortton
1049
longton               2240 lb
1050

1051
# Apothecary
1052

1053
scruple               20 grain
1054
apdram                60 grain
1055
apounce               480 grain
1056
appound               5760 grain
1057

1058
# Length
1059

1060
meter                 m
1061
cm                    centimeter
1062
mm                    millimeter
1063
km                    kilometer
1064
nm                    nanometer
1065
micron                micrometer
1066
angstrom              decinanometer
1067

1068
inch                  2.54 cm
1069
in                    inch
1070
foot                  12 in
1071
feet                  foot
1072
ft                    foot
1073
yard                  3 ft
1074
yd                    yard
1075
rod                   5.5 yd
1076
rd                    rod
1077
mile                  5280 ft
1078
mi                    mile
1079

1080
british               1200|3937 m/ft
1081
nmile                 1852m
1082

1083
acre                  4840 yd2
1084

1085
cc                    cm3
1086
liter                 kilocc
1087
ml                    milliliter
1088

1089
# US Liquid
1090

1091
gallon                231 in3
1092
imperial              1.20095
1093
gal                   gallon
1094
quart                 1|4 gal
1095
qt                    quart
1096
pint                  1|2 qt
1097
pt                    pint
1098

1099
floz                  1|16 pt
1100
fldr                  1|8 floz
1101

1102
# US Dry
1103

1104
dry                   268.8025 in3/gallon unity
1105
peck                  8 dry-quart
1106
pk                    peck
1107
bushel                4 peck
1108
bu                    bushel
1109

1110
# British
1111

1112
brgallon              277.420 in3 unity
1113
brquart               1|4 brgallon
1114
brpint                1|2 brquart
1115
brfloz                1|20 brpint
1116
brpeck                554.84 in3 unity
1117
brbushel              4 brpeck
1118

1119
# Energy Work
1120

1121
newton                kg-m/sec2
1122
nt                    newton
1123
joule                 nt-m
1124
cal                   4.1868 joule
1125

1126
# Electrical
1127

1128
coulomb               coul
1129
ampere                coul/sec
1130
amp                   ampere
1131
watt                  joule/sec
1132
volt                  watt/amp
1133
ohm                   volt/amp
1134
mho                   1/ohm
1135
siemens               mho
1136
farad                 coul/volt
1137
henry                 sec2/farad
1138
weber                 volt-sec
1139

1140
# Light
1141

1142
cd                    candela
1143
lumen                 cd sr
1144
lux                   cd sr/m2
1145

1146

1147
# Trivia
1148

1149
%                     1|100
1150
admiraltyknot         6080 ft/hr
1151
apostilb              cd/pi-m2
1152
are                   1e+2 m2
1153
arpentcan             27.52 mi
1154
arpentlin             191.835 ft
1155
astronomicalunit      au
1156
atmosphere            1.01325e+5 nt/m2
1157
atm                   atmosphere
1158
atomicmassunit        1.66044e-27 kg unity
1159
amu                   atomicmassunit
1160
bag                   94 lb
1161
bakersdozen           13
1162
bar                   1e+5 nt/m2
1163
barie                 1e-1 nt/m2
1164
barleycorn            1|3 in
1165
barn                  1e-28 m2
1166
barrel                42 gal
1167
barye                 1e-1 nt/m2
1168
bev                   1e+9 e-volt
1169
biot                  10 amp
1170
blondel               cd/pi-m2
1171
boardfoot             144 in3
1172
bolt                  40 yd
1173
bottommeasure         1|40 in
1174
britishthermalunit    1.05506e+3 joule unity
1175
btu                   britishthermalunit
1176
refrigeration         12000 btu/ton-hour
1177
cable                 720 ft
1178
caliber               1e-2 in
1179
calorie               cal
1180
carat                 205 mg
1181
cental                100 lb
1182
centesimalminute      1e-2 grade
1183
centesimalsecond      1e-4 grade
1184
century               100 year
1185
cfs                   ft3/sec
1186
chain                 66 ft
1187
circularinch          1|4 pi-in2
1188
circularmil           1e-6|4 pi-in2
1189
clusec                1e-8 mm-hg m3/s
1190
coomb                 4 bu
1191
cord                  128 ft3
1192
cordfoot              cord
1193
crith                 9.06e-2 gm
1194
cubit                 18 in
1195
cup                   1|2 pt
1196
curie                 3.7e+10 /sec
1197
dalton                amu
1198
decade                10 yr
1199
dioptre               1/m
1200
displacementton       35 ft3
1201
doppelzentner         100 kg
1202
dozen                 12
1203
drop                  .03 cm3
1204
dyne                  cm-gm/sec2
1205
electronvolt          e-volt
1206
ell                   45 in
1207
engineerschain        100 ft
1208
engineerslink         100|100 ft
1209
equivalentfootcandle  lumen/pi-ft2
1210
equivalentlux         lumen/pi-m2
1211
equivalentphot        cd/pi-cm2
1212
erg                   cm2-gm/sec2
1213
ev                    e-volt
1214
faraday               9.652e+4 coul
1215
fathom                6 ft
1216
fermi                 1e-15 m
1217
fifth                 4|5 qt
1218
finger                7|8 in
1219
firkin                9 gal
1220
footcandle            lumen/ft2
1221
footlambert           cd/pi-ft2
1222
fortnight             14 da
1223
franklin              3.33564e-10 coul
1224
frigorie              kilocal
1225
furlong               220 yd
1226
galileo               1e-2 m/sec2
1227
gamma                 1e-9 weber/m2
1228
gauss                 1e-4 weber/m2
1229
geodeticfoot          british-ft
1230
geographicalmile      1852 m
1231
gilbert               7.95775e-1 amp
1232
gill                  1|4 pt
1233
gross                 144
1234
gunterschain          22 yd
1235
hand                  4 in
1236
hectare               1e+4 m2
1237
hefnercandle          .92 cd
1238
hertz                 1/sec
1239
hogshead              2 barrel
1240
hd                    hogshead
1241
homestead             1|4 mi2
1242
horsepower            550 ft-lb-g/sec
1243
hp                    horsepower
1244
hyl                   gm force sec2/m
1245
hz                    hertz
1246
imaginarycubicfoot    1.4 ft3
1247
jeroboam              4|5 gal
1248
karat                 1|24
1249
kcal                  kilocal
1250
kcalorie              kilocal
1251
kev                   1e+3 e-volt
1252
key                   kg
1253
khz                   1e+3 /sec
1254
kilderkin             18 gal
1255
knot                  nmile/hr
1256
lambert               cd/pi-cm2
1257
langley               cal/cm2
1258
last                  80 bu
1259
league                3 mi
1260
lightyear             c-yr
1261
line                  1|12 in
1262
link                  66|100 ft
1263
longhundredweight     112 lb
1264
longquarter           28 lb
1265
lusec                 1-6 mm-hg m3/s
1266
mach                  331.46 m/sec
1267
magnum                2 qt
1268
marineleague          3 nmile
1269
maxwell               1e-8 weber
1270
metriccarat           200 mg
1271
mev                   1e+6 e-volt
1272
mgd                   megagal/day
1273
mh                    millihenry
1274
mhz                   1e+6 /sec
1275
mil                   1e-2 in
1276
millenium             1000 year
1277
minersinch            1.5 ft3/min
1278
minim                 1|60 fldr
1279
mo                    month
1280
mpg                   mile/gal
1281
mph                   mile/hr
1282
nail                  1|16 yd
1283
nauticalmile          nmile
1284
nit                   cd/m2
1285
noggin                1|8 qt
1286
nox                   1e-3 lux
1287
ns                    nanosec
1288
oersted               2.5e+2 pi-amp/m
1289
oe                    oersted
1290
pace                  36 in
1291
palm                  3 in
1292
parasang              3.5 mi
1293
parsec                au-radian/arcsec
1294
pascal                nt/m2
1295
pc                    parsec
1296
pennyweight           1|20 oz
1297
percent               %
1298
perch                 rd
1299
pf                    picofarad
1300
phot                  lumen/cm2
1301
pica                  1|6 in
1302
pieze                 1e+3 nt/m2
1303
pipe                  4 barrel
1304
point                 1|72 in
1305
poise                 gm/cm-sec
1306
pole                  rd
1307
poundal               ft-lb/sec2
1308
pdl                   poundal
1309
proof                 1|200
1310
psi                   lb-g/in2
1311
quarter               9 in
1312
quartersection        1|4 mi2
1313
quintal               100 kg
1314
quire                 25
1315
rad                   100 erg/gm
1316
ream                  500
1317
registerton           100 ft3
1318
rehoboam              156 floz
1319
rhe                   10 m2/nt-sec
1320
rontgen               2.58e-4 curie/kg
1321
rood                  1.21e+3 yd2
1322
rope                  20 ft
1323
rutherford            1e+6 /sec
1324
rydberg               1.36054e+1 ev
1325
sabin                 1 ft2
1326
sack                  3 bu
1327
seam                  8 bu
1328
section               mi2
1329
shippington           40 ft3
1330
shorthundredweight    100 lb
1331
shortquarter          25 lb
1332
sigma                 microsec
1333
skein                 120 yd
1334
skot                  1e-3 apostilb
1335
slug                  lb-g-sec2/ft
1336
span                  9 in
1337
spat                  4 pi sr
1338
spindle               14400 yd
1339
square                100 ft2
1340
stere                 m3
1341
sthene                1e+3 nt
1342
stilb                 cd/cm2
1343
stoke                 1e-4 m2/sec
1344
stone                 14 lb
1345
strike                2 bu
1346
surveyfoot            british-ft
1347
surveyorschain        66 ft
1348
surveyorslink         66|100 ft
1349
tablespoon            4 fldr
1350
teaspoon              4|3 fldr
1351
tesla                 weber/m2
1352
therm                 1e+5 btu
1353
thermie               1e+6 cal
1354
timberfoot            ft3
1355
tnt                   4.6e+6 m2/sec2
1356
tonne                 1e+6 gm
1357
torr                  mm hg
1358
township              36 mi2
1359
tun                   8 barrel
1360
water                 .22491|2.54 kg/m2-sec2
1361
wey                   40 bu
1362
weymass               252 lb
1363
Xunit                 1.00202e-13m
1364

1365
# The following entry looks like it might be the Boltzmann constant?
1366
# If so, then it is incorrect.  It should be 1.3807e-16 erg/degK.  In
1367
# any event, the temperature logic doesn't support mixed affine/linear
1368
# reductions.
1369
# - Gary Puckering
1370
// k                     1.38047e-16 erg/degC
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc