# /=====================================================================\ #
# | LaTeXML::Common::Number | #
# | Representation of numbers | #
# |=====================================================================| #
# | Part of LaTeXML: | #
# | Public domain software, produced as part of work done by the | #
# | United States Government & not subject to copyright in the US. | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov> #_# | #
# \=========================================================ooo==U==ooo=/ #
use strict;
use base qw(Exporter);
our @EXPORT = (qw(&Number));
#======================================================================
# Exported constructor.
sub Number {
my ($number) = @_;
return LaTeXML::Common::Number->new($number); }
#======================================================================
sub new {
my ($class, $number) = @_;
$number = ToString($number) if ref $number;
return bless [$number || "0"], $class; }
sub valueOf {
my ($self) = @_;
return $$self[0]; }
sub toString {
my ($self) = @_;
return $$self[0]; }
my @SCALES = (1, 10, 100, 1000, 10000, 100000);
# smallest number that makes a difference added to 1 in Perl's float format.
my $EPSILON = 1.0;
while (1.0 + $EPSILON / 2 != 1) {
$EPSILON /= 2.0; }
# Round $number to $prec decimals (0...6)
# attempting to do so portably.
sub roundto {
my ($number, $prec) = @_;
$prec = 2 unless defined $prec;
$prec = 0 if $prec < 0;
$prec = 5 if $prec > 5;
my $scale = $SCALES[$prec];
# scale to integer, w/some slop in case arbitrarily close to an integer...
my $n = $number * $scale * (1 + 100 * $EPSILON);
return int($n < -$EPSILON ? $n - 0.5 : ($n > $EPSILON ? $n + 0.5 : 0.0)) / $scale; }
sub ptValue {
my ($self, $prec) = @_;
return roundto($$self[0] / 65536, $prec); }
sub pxValue {
my ($self, $prec) = @_;
return roundto($$self[0] / 65536 * ($STATE->lookupValue('DPI') || 100 / 72.27), $prec); }
sub unlist {
my ($self) = @_;
return $self; }
sub revert {
my ($self) = @_;
return ExplodeText($self->toString); }
sub smaller {
my ($self, $other) = @_;
return ($self->valueOf < $other->valueOf) ? $self : $other; }
sub larger {
my ($self, $other) = @_;
return ($self->valueOf > $other->valueOf) ? $self : $other; }
sub absolute {
my ($self, $other) = @_;
return (ref $self)->new(abs($self->valueOf)); }
sub sign {
my ($self) = @_;
return ($self->valueOf < 0) ? -1 : (($self->valueOf > 0) ? 1 : 0); }
sub negate {
my ($self) = @_;
return (ref $self)->new(-$self->valueOf); }
sub add {
my ($self, $other) = @_;
return (ref $self)->new($self->valueOf + $other->valueOf); }
sub subtract {
my ($self, $other) = @_;
return (ref $self)->new($self->valueOf - $other->valueOf); }
# arg 2 is a number
sub multiply {
my ($self, $other) = @_;
return (ref $self)->new(int($self->valueOf * (ref $other ? $other->valueOf : $other))); }
# Truncating division
sub divide {
my ($self, $other) = @_;
return (ref $self)->new(int($self->valueOf / (ref $other ? $other->valueOf : $other))); }
# Rounding division
sub divideround {
my ($self, $other) = @_;
return (ref $self)->new(int(0.5 + $self->valueOf / (ref $other ? $other->valueOf : $other))); }
sub stringify {
my ($self) = @_;
return "Number[" . $$self[0] . "]"; }
#======================================================================
1;
__END__
=pod
=head1 NAME
C<LaTeXML::Common::Number> - representation of numbers;
extends L<LaTeXML::Common::Object>.
=head2 Exported functions
=over 4
=item C<< $number = Number($num); >>
Creates a Number object representing C<$num>.
=back
=head2 Methods
=over 4
=item C<< @tokens = $object->unlist; >>
Return a list of the tokens making up this C<$object>.
=item C<< $string = $object->toString; >>
Return a string representing C<$object>.
=item C<< $string = $object->ptValue; >>
Return a value representing C<$object> without the measurement unit (pt)
with limited decimal places.
=item C<< $string = $object->pxValue; >>
Return an integer value representing C<$object> in pixels.
Uses the state variable C<DPI> (dots per inch).
=item C<< $n = $object->valueOf; >>
Return the value in scaled points (ignoring shrink and stretch, if any).
=item C<< $n = $object->smaller($other); >>
Return C<$object> or C<$other>, whichever is smaller
=item C<< $n = $object->larger($other); >>
Return C<$object> or C<$other>, whichever is larger
=item C<< $n = $object->absolute; >>
Return an object representing the absolute value of the C<$object>.
=item C<< $n = $object->sign; >>
Return an integer: -1 for negatives, 0 for 0 and 1 for positives
=item C<< $n = $object->negate; >>
Return an object representing the negative of the C<$object>.
=item C<< $n = $object->add($other); >>
Return an object representing the sum of C<$object> and C<$other>
=item C<< $n = $object->subtract($other); >>
Return an object representing the difference between C<$object> and C<$other>
=item C<< $n = $object->multiply($n); >>
Return an object representing the product of C<$object> and C<$n> (a regular number).
=item C<< $n = $object->divide($n); >>
Return an object representing the (truncating) division of C<$object> by C<$n> (a regular number).
=item C<< $n = $object->divideround($n); >>
Return an object representing the (rounding) division of C<$object> by C<$n> (a regular number).
=back
=head1 AUTHOR
Bruce Miller <bruce.miller@nist.gov>
=head1 COPYRIGHT
Public domain software, produced as part of work done by the
United States Government & not subject to copyright in the US.
=cut