Annotation of loncom/homework/math_parser/Quantity.pm, revision 1.2

1.1       damieng     1: # The LearningOnline Network with CAPA - LON-CAPA
                      2: # Quantity
                      3: #
1.2     ! raeburn     4: # $Id: Quantity.pm,v 1.2 2023/03/13 18:30:00 raeburn Exp $
        !             5: #
1.1       damieng     6: # Copyright (C) 2014 Michigan State University Board of Trustees
                      7: #
                      8: # This program is free software: you can redistribute it and/or modify
                      9: # it under the terms of the GNU General Public License as published by
                     10: # the Free Software Foundation, either version 3 of the License, or
                     11: # (at your option) any later version.
                     12: #
                     13: # This program is distributed in the hope that it will be useful,
                     14: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     15: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
                     16: # GNU General Public License for more details.
                     17: #
                     18: # You should have received a copy of the GNU General Public License
                     19: # along with this program. If not, see <http://www.gnu.org/licenses/>.
                     20: #
                     21: 
                     22: ##
                     23: # A quantity (value and units)
                     24: ##
                     25: package Apache::math_parser::Quantity;
                     26: 
                     27: use strict;
                     28: use warnings;
                     29: use utf8;
                     30: 
                     31: use POSIX;
                     32: use Math::Complex; # must be after POSIX for redefinition of log10
                     33: 
                     34: use aliased 'Apache::math_parser::CalcException';
                     35: use aliased 'Apache::math_parser::Quantity';
                     36: use aliased 'Apache::math_parser::QVector';
                     37: use aliased 'Apache::math_parser::QMatrix';
                     38: use aliased 'Apache::math_parser::QSet';
                     39: use aliased 'Apache::math_parser::QInterval';
                     40: use aliased 'Apache::math_parser::QIntervalUnion';
                     41: 
                     42: use overload
                     43:     '""' => \&toString,
                     44:     '+' => \&qadd,
                     45:     '-' => \&qsub,
                     46:     '*' => \&qmult,
                     47:     '/' => \&qdiv,
                     48:     '^' => \&qpow,
                     49:     '<' => \&qlt,
                     50:     '<=' => \&qle,
                     51:     '>' => \&qgt,
                     52:     '>=' => \&qge,
                     53:     '<=>' => \&perl_compare;
                     54: 
                     55: # compare() return codes:
                     56: use enum qw(IDENTICAL WRONG_TYPE WRONG_DIMENSIONS MISSING_UNITS ADDED_UNITS WRONG_UNITS WRONG_VALUE WRONG_ENDPOINT);
                     57: 
                     58: 
                     59: ##
                     60: # Constructor
                     61: # @param {complex} value
                     62: # @optional {Object.<string, integer>} units - hash: unit name -> exponent for each SI unit
                     63: ##
                     64: sub new {
                     65:     my $class = shift;
                     66:     my $self = {
                     67:         _value => shift,
                     68:         _units => shift,
                     69:     };
                     70:     if ("".$self->{_value} eq "i") {
                     71:         $self->{_value} = i;
                     72:     } elsif ("".$self->{_value} eq "inf") {
                     73:         $self->{_value} = 9**9**9;
                     74:     }
                     75:     if (!defined $self->{_units}) {
                     76:         $self->{_units} = {
                     77:             s => 0,
                     78:             m => 0,
                     79:             kg => 0,
                     80:             K => 0,
                     81:             A => 0,
                     82:             mol => 0,
                     83:             cd => 0
                     84:         };
                     85:     } else {
                     86:         foreach my $unit ('s', 'm', 'kg', 'K', 'A', 'mol', 'cd') {
                     87:             if (!defined $self->{_units}->{$unit}) {
                     88:                 $self->{_units}->{$unit} = 0;
                     89:             }
                     90:         }
                     91:     }
                     92:     bless $self, $class;
                     93:     return $self;
                     94: }
                     95: 
                     96: # Attribute helpers
                     97: 
                     98: ##
                     99: # Value.
                    100: # @returns {Complex}
                    101: ##
                    102: sub value {
                    103:     my $self = shift;
                    104:     return $self->{_value};
                    105: }
                    106: 
                    107: 
                    108: ##
                    109: # Units
                    110: # @returns {Object.<string, integer>} hash: unit name -> exponent for each SI unit
                    111: ##
                    112: sub units {
                    113:     my $self = shift;
                    114:     return $self->{_units};
                    115: }
                    116: 
                    117: 
                    118: ##
                    119: # Returns a readable view of the object
                    120: # @returns {string}
                    121: ##
                    122: sub toString {
                    123:     my ( $self ) = @_;
                    124:     my $s;
                    125:     # complex display in polar notation can be confused with vectors
                    126:     # normally we should just have to call 	Math::Complex::display_format('cartesian');
                    127:     # actually, it's supposed to be the default...
                    128:     # but this is not working, so...
                    129:     if ($self->value =~ /\[/) {
                    130:         my $v = $self->value;
                    131:         $v->display_format('cartesian');
                    132:         $s = "".$v;
                    133:     } else {
                    134:         $s = $self->value;
                    135:     }
                    136:     foreach my $unit (keys %{$self->units}) {
                    137:         my $e = $self->units->{$unit};
                    138:         if ($e != 0) {
                    139:             $s .= " ".$unit;
                    140:             if ($e != 1) {
                    141:                 $s .= "^".$e;
                    142:             }
                    143:         }
                    144:     }
                    145:     return $s;
                    146: }
                    147: 
                    148: ##
                    149: # Equality test
                    150: # @param {Quantity}
                    151: # @optional {string|float} tolerance
                    152: # @returns {boolean}
                    153: ##
                    154: sub equals {
                    155:     my ( $self, $q, $tolerance ) = @_;
                    156:     if (!$q->isa(Quantity)) {
                    157:         return 0;
                    158:     }
                    159:     if (!defined $tolerance) {
                    160:         $tolerance = 0;
                    161:     }
                    162:     if ($tolerance =~ /%/) {
                    163:         my $perc = $tolerance;
                    164:         $perc =~ s/%//;
                    165:         $perc /= 100;
                    166:         if (abs($self->value - $q->value) > abs($self->value * $perc)) {
                    167:             return 0;
                    168:         }
                    169:     } else {
                    170:         if (abs($self->value - $q->value) > $tolerance) {
                    171:             return 0;
                    172:         }
                    173:     }
                    174:     my %units = %{$self->units};
                    175:     foreach my $unit (keys %units) {
                    176:         if ($units{$unit} != $q->units->{$unit}) {
                    177:             return 0;
                    178:         }
                    179:     }
                    180:     return 1;
                    181: }
                    182: 
                    183: ##
                    184: # Compare this quantity with another one, and returns a code.
                    185: # Returns Quantity->WRONG_TYPE if the parameter is not a Quantity.
                    186: # @param {Quantity|QVector|QMatrix|QSet|QInterval} q
                    187: # @optional {string|float} tolerance
                    188: # @returns {int} WRONG_TYPE|MISSING_UNITS|ADDED_UNITS|WRONG_UNITS|WRONG_VALUE|IDENTICAL
                    189: ##
                    190: sub compare {
                    191:     my ( $self, $q, $tolerance ) = @_;
                    192:     if (!$q->isa(Quantity)) {
                    193:         return WRONG_TYPE;
                    194:     }
                    195:     if (!defined $tolerance) {
                    196:         $tolerance = 0;
                    197:     }
                    198:     my %units = %{$self->units};
                    199:     my $this_has_units = 0;
                    200:     my $other_has_units = 0;
                    201:     my $wrong_units = 0;
                    202:     foreach my $unit (keys %units) {
                    203:         if ($units{$unit} != 0) {
                    204:             $this_has_units = 1;
                    205:         }
                    206:         if ($q->units->{$unit} != 0) {
                    207:             $other_has_units = 1;
                    208:         }
                    209:         if ($units{$unit} != $q->units->{$unit}) {
                    210:             $wrong_units = 1;
                    211:         }
                    212:     }
                    213:     if ($this_has_units && !$other_has_units) {
                    214:         return MISSING_UNITS;
                    215:     } elsif (!$this_has_units && $other_has_units) {
                    216:         return ADDED_UNITS;
                    217:     }
                    218:     if ($wrong_units) {
                    219:         return WRONG_UNITS;
                    220:     }
                    221:     if ($tolerance =~ /%/) {
                    222:         my $perc = $tolerance;
                    223:         $perc =~ s/%//;
                    224:         $perc /= 100;
                    225:         if (abs($self->value - $q->value) > abs($self->value * $perc)) {
                    226:             return WRONG_VALUE;
                    227:         }
                    228:     } else {
                    229:         if (abs($self->value - $q->value) > $tolerance) {
                    230:             return WRONG_VALUE;
                    231:         }
                    232:     }
                    233:     return IDENTICAL;
                    234: }
                    235: 
                    236: ##
                    237: # <=> operator.
                    238: # Compare this quantity with another one, and returns -1, 0 or 1.
                    239: # @param {Quantity} q
                    240: # @returns {int}
                    241: ##
                    242: sub perl_compare {
                    243:     my ( $self, $q ) = @_;
                    244:     if (!$q->isa(Quantity)) {
                    245:         die CalcException->new("Quantity comparison: second member is not a quantity.");
                    246:     }
                    247:     $self->unitsMatch($q, 'perl_compare');
                    248:     return($self->value <=> $q->value);
                    249: }
                    250: 
                    251: ##
                    252: # Not equal
                    253: # @param {Quantity} q
                    254: # @optional {string|float} tolerance
                    255: # @returns {boolean}
                    256: ##
                    257: sub ne {
                    258:     my ( $self, $q, $tolerance ) = @_;
                    259:     if ($self->equals($q, $tolerance)) {
                    260:         return(0);
                    261:     } else {
                    262:         return(1);
                    263:     }
                    264: }
                    265: 
                    266: ##
                    267: # Less than
                    268: # @param {Quantity} q
                    269: # @returns {boolean}
                    270: ##
                    271: sub lt {
                    272:     my ( $self, $q ) = @_;
                    273:     if (!$q->isa(Quantity)) {
                    274:         die CalcException->new("Quantity smaller than: second member is not a quantity.");
                    275:     }
                    276:     $self->unitsMatch($q, 'lt');
                    277:     if ($self->value < $q->value) {
                    278:         return(1);
                    279:     } else {
                    280:         return(0);
                    281:     }
                    282: }
                    283: 
                    284: ##
                    285: # Less than or equal
                    286: # @param {Quantity} q
                    287: # @returns {boolean}
                    288: ##
                    289: sub le {
                    290:     my ( $self, $q ) = @_;
                    291:     if (!$q->isa(Quantity)) {
                    292:         die CalcException->new("Quantity smaller or equal: second member is not a quantity.");
                    293:     }
                    294:     $self->unitsMatch($q, 'le');
                    295:     if ($self->value <= $q->value) {
                    296:         return(1);
                    297:     } else {
                    298:         return(0);
                    299:     }
                    300: }
                    301: 
                    302: ##
                    303: # Greater than
                    304: # @param {Quantity} q
                    305: # @returns {boolean}
                    306: ##
                    307: sub gt {
                    308:     my ( $self, $q ) = @_;
                    309:     if (!$q->isa(Quantity)) {
                    310:         die CalcException->new("Quantity greater than: second member is not a quantity.");
                    311:     }
                    312:     $self->unitsMatch($q, 'gt');
                    313:     if ($self->value > $q->value) {
                    314:         return(1);
                    315:     } else {
                    316:         return(0);
                    317:     }
                    318: }
                    319: 
                    320: ##
                    321: # Greater than or equal
                    322: # @param {Quantity} q
                    323: # @returns {boolean}
                    324: ##
                    325: sub ge {
                    326:     my ( $self, $q ) = @_;
                    327:     if (!$q->isa(Quantity)) {
                    328:         die CalcException->new("Quantity greater or equal: second member is not a quantity.");
                    329:     }
                    330:     $self->unitsMatch($q, 'ge');
                    331:     if ($self->value >= $q->value) {
                    332:         return(1);
                    333:     } else {
                    334:         return(0);
                    335:     }
                    336: }
                    337: 
                    338: ##
                    339: # Clone this object
                    340: # @returns {Quantity}
                    341: ##
                    342: sub clone {
                    343:     my ( $self ) = @_;
                    344:     my %units = %{$self->units};
                    345:     return Quantity->new($self->value, \%units);
                    346: }
                    347: 
                    348: ##
                    349: # Addition
                    350: # @param {Quantity} q
                    351: # @returns {Quantity}
                    352: ##
                    353: sub qadd {
                    354:     my ( $self, $q ) = @_;
                    355:     if (!$q->isa(Quantity)) {
                    356:         die CalcException->new("Quantity addition: second member is not a quantity.");
                    357:     }
                    358:     my $v = $self->value + $q->value;
                    359:     $self->unitsMatch($q, 'addition');
                    360:     return Quantity->new($v, $self->units);
                    361: }
                    362: 
                    363: ##
                    364: # Substraction
                    365: # @param {Quantity} q
                    366: # @returns {Quantity}
                    367: ##
                    368: sub qsub {
                    369:     my ( $self, $q ) = @_;
                    370:     if (!$q->isa(Quantity)) {
                    371:         die CalcException->new("Quantity substraction: second member is not a quantity.");
                    372:     }
                    373:     my $v = $self->value - $q->value;
                    374:     $self->unitsMatch($q, 'substraction');
                    375:     return Quantity->new($v, $self->units);
                    376: }
                    377: 
                    378: ##
                    379: # Negation
                    380: # @returns {Quantity}
                    381: ##
                    382: sub qneg {
                    383:     my ( $self ) = @_;
                    384:     my $v = - $self->value;
                    385:     my %units = %{$self->units};
                    386:     return Quantity->new($v, \%units);
                    387: }
                    388: 
                    389: ##
                    390: # Multiplication
                    391: # @param {Quantity|QVector|QMatrix|QSet|QInterval|QIntervalUnion} qv
                    392: # @returns {Quantity|QVector|QMatrix|QSet|QInterval|QIntervalUnion}
                    393: ##
                    394: sub qmult {
                    395:     my ( $self, $qv ) = @_;
                    396:     if (!$qv->isa(Quantity) && !$qv->isa(QVector) && !$qv->isa(QMatrix) &&
                    397:             !$qv->isa(QSet) && !$qv->isa(QInterval) && !$qv->isa(QIntervalUnion)) {
                    398:         die CalcException->new("Cannot multiply with something that is not a quantity, vector, matrix, set, or interval.");
                    399:     }
                    400:     if ($qv->isa(QVector) || $qv->isa(QMatrix) || $qv->isa(QSet) || $qv->isa(QInterval) || $qv->isa(QIntervalUnion)) {
                    401:         return($qv->qmult($self));
                    402:     }
                    403:     my $q = $qv;
                    404:     my $v = $self->value * $q->value;
                    405:     my %units = %{$self->units};
                    406:     foreach my $unit (keys %units) {
                    407:         $units{$unit} = $units{$unit} + $q->units->{$unit};
                    408:     }
                    409:     return Quantity->new($v, \%units);
                    410: }
                    411: 
                    412: ##
                    413: # Division
                    414: # @param {Quantity} q
                    415: # @returns {Quantity}
                    416: ##
                    417: sub qdiv {
                    418:     my ( $self, $q ) = @_;
                    419:     if (!$q->isa(Quantity)) {
                    420:         die CalcException->new("Cannot divide by something that is not a quantity.");
                    421:     }
                    422:     if ($q->value == 0) {
                    423:         die CalcException->new("Division by zero.");
                    424:     }
                    425:     my $v = $self->value / $q->value;
                    426:     my %units = %{$self->units};
                    427:     foreach my $unit (keys %units) {
                    428:         $units{$unit} = $units{$unit} - $q->units->{$unit};
                    429:     }
                    430:     return Quantity->new($v, \%units);
                    431: }
                    432: 
                    433: ##
                    434: # Power
                    435: # @param {Quantity} q
                    436: # @returns {Quantity}
                    437: ##
                    438: sub qpow {
                    439:     my ( $self, $q ) = @_;
                    440:     if (!$q->isa(Quantity)) {
                    441:         die CalcException->new("Cannot raise to the power of something that is not a number.");
                    442:     }
                    443:     my $v = $self->value ** $q->value;
                    444:     $q->noUnits("Power");
                    445:     my %units = %{$self->units};
                    446:     foreach my $unit (keys %{$q->units}) {
                    447:         $units{$unit} = $units{$unit} * $q->value;
                    448:     }
                    449:     return Quantity->new($v, \%units);
                    450: }
                    451: 
                    452: ##
                    453: # Factorial
                    454: # @returns {Quantity}
                    455: ##
                    456: sub qfact {
                    457:     my ( $self ) = @_;
                    458:     my $v = $self->value;
                    459:     if ($v < 0) {
                    460:         die CalcException->new("Factorial of a number smaller than zero.");
                    461:     }
                    462:     # should check if integer
                    463:     my $n = $v;
                    464:     for (my $i=$n - 1; $i > 1; $i--) {
                    465:         $v *= $i;
                    466:     }
                    467:     return Quantity->new($v, $self->units);
                    468: }
                    469: 
                    470: ##
                    471: # Square root
                    472: # @returns {Quantity}
                    473: ##
                    474: sub qsqrt {
                    475:     my ( $self ) = @_;
                    476:     my $v = sqrt($self->value);
                    477:     my %units = %{$self->units};
                    478:     foreach my $unit (keys %units) {
                    479:         $units{$unit} = $units{$unit} / 2;
                    480:     }
                    481:     return Quantity->new($v, \%units);
                    482: }
                    483: 
                    484: ##
                    485: # Absolute value
                    486: # @returns {Quantity}
                    487: ##
                    488: sub qabs {
                    489:     my ( $self ) = @_;
                    490:     my $v = abs($self->value);
                    491:     my %units = %{$self->units};
                    492:     return Quantity->new($v, \%units);
                    493: }
                    494: 
                    495: ##
                    496: # Exponential
                    497: # @returns {Quantity}
                    498: ##
                    499: sub qexp {
                    500:     my ( $self ) = @_;
                    501:     $self->noUnits("exp");
                    502:     return Quantity->new(exp($self->value), $self->units);
                    503: }
                    504: 
                    505: ##
                    506: # Natural logarithm
                    507: # @returns {Quantity}
                    508: ##
                    509: sub qln {
                    510:     my ( $self ) = @_;
                    511:     $self->noUnits("ln");
                    512:     # this will return a complex if the value is < 0
                    513:     #if ($self->value < 0) {
                    514:     #    die CalcException->new("Ln of number < 0");
                    515:     #}
                    516:     if ($self->value == 0) {
                    517:         die CalcException->new("Natural logarithm of zero.");
                    518:     }
                    519:     return Quantity->new(log($self->value), $self->units);
                    520: }
                    521: 
                    522: ##
                    523: # Decimal logarithm
                    524: # @returns {Quantity}
                    525: ##
                    526: sub qlog10 {
                    527:     my ( $self ) = @_;
                    528:     $self->noUnits("log10");
                    529:     # this will return a complex if the value is < 0
                    530:     #if ($self->value < 0) {
                    531:     #    die CalcException->new("Log10 of number < 0");
                    532:     #}
                    533:     if ($self->value == 0) {
                    534:         die CalcException->new("Logarithm of zero.");
                    535:     }
                    536:     return Quantity->new(log10($self->value), $self->units);
                    537: }
                    538: 
                    539: ##
                    540: # Modulo
                    541: # @param {Quantity} q
                    542: # @returns {Quantity}
                    543: ##
                    544: sub qmod {
                    545:     my ( $self, $q ) = @_;
                    546:     if (!$q->isa(Quantity)) {
                    547:         die CalcException->new("Cannot calculate the modulus with respect to something that is not a quantity.");
                    548:     }
                    549:     my $v = $self->value % $q->value;
                    550:     return Quantity->new($v, $self->units);
                    551: }
                    552: 
                    553: ##
                    554: # Returns -1, 0 or 1 depending on the sign of the value
                    555: # @returns {Quantity}
                    556: ##
                    557: sub qsgn {
                    558:     my ( $self ) = @_;
                    559:     my $v;
                    560:     if ($self->value < 0) {
                    561:         $v = -1;
                    562:     } elsif ($self->value > 0) {
                    563:         $v = 1;
                    564:     } else {
                    565:         $v = 0;
                    566:     }
                    567:     return Quantity->new($v, $self->units);
                    568: }
                    569: 
                    570: ##
                    571: # Returns the least integer that is greater than or equal to the value.
                    572: # @returns {Quantity}
                    573: ##
                    574: sub qceil {
                    575:     my ( $self ) = @_;
                    576:     my $v = ceil($self->value);
                    577:     return Quantity->new($v, $self->units);
                    578: }
                    579: 
                    580: ##
                    581: # Returns the largest integer that is less than or equal to the value.
                    582: # @returns {Quantity}
                    583: ##
                    584: sub qfloor {
                    585:     my ( $self ) = @_;
                    586:     my $v = floor($self->value);
                    587:     return Quantity->new($v, $self->units);
                    588: }
                    589: 
                    590: ##
                    591: # Sine
                    592: # @returns {Quantity}
                    593: ##
                    594: sub qsin {
                    595:     my ( $self ) = @_;
                    596:     $self->noUnits("sin");
                    597:     return Quantity->new(sin($self->value), $self->units);
                    598: }
                    599: 
                    600: ##
                    601: # Cosine
                    602: # @returns {Quantity}
                    603: ##
                    604: sub qcos {
                    605:     my ( $self ) = @_;
                    606:     $self->noUnits("cos");
                    607:     return Quantity->new(cos($self->value), $self->units);
                    608: }
                    609: 
                    610: ##
                    611: # Tangent
                    612: # @returns {Quantity}
                    613: ##
                    614: sub qtan {
                    615:     my ( $self ) = @_;
                    616:     $self->noUnits("tan");
                    617:     return Quantity->new(tan($self->value), $self->units);
                    618: }
                    619: 
                    620: ##
                    621: # Arcsinus
                    622: # @returns {Quantity}
                    623: ##
                    624: sub qasin {
                    625:     my ( $self ) = @_;
                    626:     $self->noUnits("asin");
                    627:     return Quantity->new(asin($self->value), $self->units);
                    628: }
                    629: 
                    630: ##
                    631: # Arccosinus
                    632: # @returns {Quantity}
                    633: ##
                    634: sub qacos {
                    635:     my ( $self ) = @_;
                    636:     $self->noUnits("acos");
                    637:     return Quantity->new(acos($self->value), $self->units);
                    638: }
                    639: 
                    640: ##
                    641: # Arctangent
                    642: # @returns {Quantity}
                    643: ##
                    644: sub qatan {
                    645:     my ( $self ) = @_;
                    646:     $self->noUnits("atan");
                    647:     return Quantity->new(atan($self->value), $self->units);
                    648: }
                    649: 
                    650: ##
                    651: # Arctangent of self/x in the range -pi to pi
                    652: # @param {Quantity} x
                    653: # @returns {Quantity}
                    654: ##
                    655: sub qatan2 {
                    656:     my ( $self, $q ) = @_;
                    657:     if (!$q->isa(Quantity)) {
                    658:         die CalcException->new("Cannot calculate atan2 if second argument is not a quantity.");
                    659:     }
                    660:     $self->noUnits("atan2");
                    661:     my $v = atan2($self->value, $q->value);
                    662:     return Quantity->new($v, $self->units);
                    663: }
                    664: 
                    665: ##
                    666: # Hyperbolic sinus
                    667: # @returns {Quantity}
                    668: ##
                    669: sub qsinh {
                    670:     my ( $self ) = @_;
                    671:     $self->noUnits("sinh");
                    672:     return Quantity->new(sinh($self->value), $self->units);
                    673: }
                    674: 
                    675: ##
                    676: # Hyperbolic cosinus
                    677: # @returns {Quantity}
                    678: ##
                    679: sub qcosh {
                    680:     my ( $self ) = @_;
                    681:     $self->noUnits("cosh");
                    682:     return Quantity->new(cosh($self->value), $self->units);
                    683: }
                    684: 
                    685: ##
                    686: # Hyperbolic tangent
                    687: # @returns {Quantity}
                    688: ##
                    689: sub qtanh {
                    690:     my ( $self ) = @_;
                    691:     $self->noUnits("tanh");
                    692:     return Quantity->new(tanh($self->value), $self->units);
                    693: }
                    694: 
                    695: ##
                    696: # Hyperbolic arcsinus
                    697: # @returns {Quantity}
                    698: ##
                    699: sub qasinh {
                    700:     my ( $self ) = @_;
                    701:     $self->noUnits("asinh");
                    702:     return Quantity->new(asinh($self->value), $self->units);
                    703: }
                    704: 
                    705: ##
                    706: # Hyperbolic arccosinus
                    707: # @returns {Quantity}
                    708: ##
                    709: sub qacosh {
                    710:     my ( $self ) = @_;
                    711:     $self->noUnits("acosh");
                    712:     return Quantity->new(acosh($self->value), $self->units);
                    713: }
                    714: 
                    715: ##
                    716: # Hyperbolic arctangent
                    717: # @returns {Quantity}
                    718: ##
                    719: sub qatanh {
                    720:     my ( $self ) = @_;
                    721:     $self->noUnits("atanh");
                    722:     return Quantity->new(atanh($self->value), $self->units);
                    723: }
                    724: 
                    725: ##
                    726: # Equals
                    727: # @param {Quantity|QVector|QMatrix|QSet|QInterval} q
                    728: # @optional {string|float} tolerance
                    729: # @returns {Quantity}
                    730: ##
                    731: sub qeq {
                    732:     my ( $self, $q, $tolerance ) = @_;
                    733:     my $v = $self->equals($q, $tolerance);
                    734:     return Quantity->new($v);
                    735: }
                    736: 
                    737: ##
                    738: # Less than
                    739: # @param {Quantity}
                    740: # @returns {Quantity}
                    741: ##
                    742: sub qlt {
                    743:     my ( $self, $q ) = @_;
                    744:     my $v = $self->lt($q);
                    745:     return Quantity->new($v);
                    746: }
                    747: 
                    748: ##
                    749: # Less than or equal
                    750: # @param {Quantity} q
                    751: # @returns {Quantity}
                    752: ##
                    753: sub qle {
                    754:     my ( $self, $q ) = @_;
                    755:     my $v = $self->le($q);
                    756:     return Quantity->new($v);
                    757: }
                    758: 
                    759: ##
                    760: # Greater than
                    761: # @param {Quantity} q
                    762: # @returns {Quantity}
                    763: ##
                    764: sub qgt {
                    765:     my ( $self, $q ) = @_;
                    766:     my $v = $self->gt($q);
                    767:     return Quantity->new($v);
                    768: }
                    769: 
                    770: ##
                    771: # Greater than or equal
                    772: # @param {Quantity} q
                    773: # @returns {Quantity}
                    774: ##
                    775: sub qge {
                    776:     my ( $self, $q ) = @_;
                    777:     my $v = $self->ge($q);
                    778:     return Quantity->new($v);
                    779: }
                    780: 
                    781: ##
                    782: # Dies if units do not match.
                    783: ##
                    784: sub unitsMatch {
                    785:     my ( $self, $q, $fct_name ) = @_;
                    786:     my %units = %{$self->units};
                    787:     foreach my $unit (keys %units) {
                    788:         if ($units{$unit} != $q->units->{$unit}) {
                    789:             die CalcException->new("Units [_1] do not match.", $fct_name);
                    790:         }
                    791:     }
                    792: }
                    793: 
                    794: ##
                    795: # Dies if there are any unit.
                    796: ##
                    797: sub noUnits {
                    798:     my ( $self, $fct_name ) = @_;
                    799:     my %units = %{$self->units};
                    800:     foreach my $unit (keys %units) {
                    801:         if ($units{$unit} != 0) {
                    802:             die CalcException->new("Cannot calculate [_1] of something with units.", $fct_name);
                    803:         }
                    804:     }
                    805: }
                    806: 
                    807: 1;
                    808: __END__

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>