1# /=====================================================================\ #
2# |  LaTeXML::Common::Number                                            | #
3# | Representation of numbers                                           | #
4# |=====================================================================| #
5# | Part of LaTeXML:                                                    | #
6# |  Public domain software, produced as part of work done by the       | #
7# |  United States Government & not subject to copyright in the US.     | #
8# |---------------------------------------------------------------------| #
9# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
10# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
11# \=========================================================ooo==U==ooo=/ #
12package LaTeXML::Common::Number;
13use LaTeXML::Global;
14use strict;
15use warnings;
16use LaTeXML::Common::Object;
17use LaTeXML::Core::Token;
18use base qw(LaTeXML::Common::Object);
19use base qw(Exporter);
20our @EXPORT = (qw(&Number &roundto));
21
22#======================================================================
23# Exported constructor.
24
25sub Number {
26  my ($number) = @_;
27  return LaTeXML::Common::Number->new($number); }
28
29#======================================================================
30
31sub new {
32  my ($class, $number) = @_;
33  $number = ToString($number) if ref $number;
34  return bless [$number || "0"], $class; }
35
36sub valueOf {
37  my ($self) = @_;
38  return $$self[0]; }
39
40sub toString {
41  my ($self) = @_;
42  return $$self[0]; }
43
44my @SCALES = (1, 10, 100, 1000, 10000, 100000);
45
46# smallest number that makes a difference added to 1 in Perl's float format.
47my $EPSILON = 1.0;
48while (1.0 + $EPSILON / 2 != 1) {
49  $EPSILON /= 2.0; }
50
51# Round $number to $prec decimals (0...6)
52# attempting to do so portably.
53sub roundto {
54  my ($number, $prec) = @_;
55  $prec = 2 unless defined $prec;
56  $prec = 0 if $prec < 0;
57  $prec = 5 if $prec > 5;
58  my $scale = $SCALES[$prec];
59  # scale to integer, w/some slop in case arbitrarily close to an integer...
60  my $n = $number * $scale * (1 + 100 * $EPSILON);
61  return int($n < -$EPSILON ? $n - 0.5 : ($n > $EPSILON ? $n + 0.5 : 0.0)) / $scale; }
62
63sub ptValue {
64  my ($self, $prec) = @_;
65  return roundto($$self[0] / 65536, $prec); }
66
67sub pxValue {
68  my ($self, $prec) = @_;
69  return roundto($$self[0] / 65536 * ($STATE->lookupValue('DPI') || 100 / 72.27), $prec); }
70
71sub unlist {
72  my ($self) = @_;
73  return $self; }
74
75sub revert {
76  my ($self) = @_;
77  return ExplodeText($self->toString); }
78
79sub smaller {
80  my ($self, $other) = @_;
81  return ($self->valueOf < $other->valueOf) ? $self : $other; }
82
83sub larger {
84  my ($self, $other) = @_;
85  return ($self->valueOf > $other->valueOf) ? $self : $other; }
86
87sub absolute {
88  my ($self, $other) = @_;
89  return (ref $self)->new(abs($self->valueOf)); }
90
91sub sign {
92  my ($self) = @_;
93  return ($self->valueOf < 0) ? -1 : (($self->valueOf > 0) ? 1 : 0); }
94
95sub negate {
96  my ($self) = @_;
97  return (ref $self)->new(-$self->valueOf); }
98
99sub add {
100  my ($self, $other) = @_;
101  return (ref $self)->new($self->valueOf + $other->valueOf); }
102
103sub subtract {
104  my ($self, $other) = @_;
105  return (ref $self)->new($self->valueOf - $other->valueOf); }
106
107# arg 2 is a number
108sub multiply {
109  my ($self, $other) = @_;
110  return (ref $self)->new(int($self->valueOf * (ref $other ? $other->valueOf : $other))); }
111
112# Truncating division
113sub divide {
114  my ($self, $other) = @_;
115  return (ref $self)->new(int($self->valueOf / (ref $other ? $other->valueOf : $other))); }
116
117# Rounding division
118sub divideround {
119  my ($self, $other) = @_;
120  return (ref $self)->new(int(0.5 + $self->valueOf / (ref $other ? $other->valueOf : $other))); }
121
122sub stringify {
123  my ($self) = @_;
124  return "Number[" . $$self[0] . "]"; }
125
126#======================================================================
1271;
128
129__END__
130
131=pod
132
133=head1 NAME
134
135C<LaTeXML::Common::Number> - representation of numbers;
136extends L<LaTeXML::Common::Object>.
137
138=head2 Exported functions
139
140=over 4
141
142=item C<< $number = Number($num); >>
143
144Creates a Number object representing C<$num>.
145
146=back
147
148=head2 Methods
149
150=over 4
151
152=item C<< @tokens = $object->unlist; >>
153
154Return a list of the tokens making up this C<$object>.
155
156=item C<< $string = $object->toString; >>
157
158Return a string representing C<$object>.
159
160=item C<< $string = $object->ptValue; >>
161
162Return a value representing C<$object> without the measurement unit (pt)
163with limited decimal places.
164
165=item C<< $string = $object->pxValue; >>
166
167Return an integer value representing C<$object> in pixels.
168Uses the state variable C<DPI> (dots per inch).
169
170=item C<< $n = $object->valueOf; >>
171
172Return the value in scaled points (ignoring shrink and stretch, if any).
173
174=item C<< $n = $object->smaller($other); >>
175
176Return C<$object> or C<$other>, whichever is smaller
177
178=item C<< $n = $object->larger($other); >>
179
180Return C<$object> or C<$other>, whichever is larger
181
182=item C<< $n = $object->absolute; >>
183
184Return an object representing the absolute value of the C<$object>.
185
186=item C<< $n = $object->sign; >>
187
188Return an integer: -1 for negatives, 0 for 0 and 1 for positives
189
190=item C<< $n = $object->negate; >>
191
192Return an object representing the negative of the C<$object>.
193
194=item C<< $n = $object->add($other); >>
195
196Return an object representing the sum of C<$object> and C<$other>
197
198=item C<< $n = $object->subtract($other); >>
199
200Return an object representing the difference between C<$object> and C<$other>
201
202=item C<< $n = $object->multiply($n); >>
203
204Return an object representing the product of C<$object> and C<$n> (a regular number).
205
206=item C<< $n = $object->divide($n); >>
207
208Return an object representing the (truncating) division of C<$object> by C<$n> (a regular number).
209
210=item C<< $n = $object->divideround($n); >>
211
212Return an object representing the (rounding) division of C<$object> by C<$n> (a regular number).
213
214=back
215
216=head1 AUTHOR
217
218Bruce Miller <bruce.miller@nist.gov>
219
220=head1 COPYRIGHT
221
222Public domain software, produced as part of work done by the
223United States Government & not subject to copyright in the US.
224
225=cut
226
227