package Number::WithError::LaTeX; use 5.008; use strict; use warnings; our $VERSION = '0.06'; use base 'Number::WithError'; use base 'Exporter'; our %EXPORT_TAGS = %Number::WithError::EXPORT_TAGS; our @EXPORT_OK = @Number::WithError::EXPORT_OK; use TeX::Encode; use Encode (); use Carp qw/croak/; sub witherror { Number::WithError::LaTeX->new(@_) } sub witherror_big { Number::WithError::LaTeX->new_big(@_) } use Params::Util qw/_ARRAY0/; =head1 NAME Number::WithError::LaTeX - LaTeX output for Number::WithError =head1 SYNOPSIS use Number::WithError::LaTeX; my $num = Number::WithError::LaTeX->new(5.647, 0.31); print $num . "\n"; # prints '5.65e+00 +/- 3.1e-01' # (I.e. it automatically does scientific rounding) print $num->latex() . "\n"; # prints '5.65 \cdot 10^{0} \pm 3.1 \cdot 10^{-1}' print $num->latex(radix => ',', enclose => '$') . "\n"; # prints '$5,\!65 \cdot 10^{0} \pm 3,\!1 \cdot 10^{-1}$' print $num->encode("This will encode an e-acute (".chr(0xe9).") as \\'e") . "\n"; # Delegated to TeX::Encode::encode(). # prints 'This is a German umlaut: \"a' =head1 DESCRIPTION This class is a subclass of L. It provides the same interface and the same exports. It adds several methods to every object. The main functionality is provided by C, which dumps the object as valid LaTeX code. Also, C is a convenient way to encode any UTF-8 string into TeX. It is just a convenience thing since it is delegated to L. Unlike C, this module requires perl version 5.8 or later. (That is the rationale for creating a separate distribution, too.) =head1 EXPORT This module exports the following subroutines on demand. It supports the C<:all> Exporter tag to export all of them. The subroutines are documented in L. =head2 witherror =head2 witherror_big =cut =head1 METHODS This is a list of public methods. =head2 latex This method stringifies the object as valid LaTeX code. The returned string is valid in a LaTeX math mode. That means, you will have to enclose it in dollars or in an C environment by default. The method takes named parameters. All parameters are optional. The C parameter can set a string to enclose the produced latex code in. This can be either a simple string like C<$> or an array reference containing two strings. Those two strings will be used for the start and end respectively. (For environments.) Example: (let C<$obj> be '5.6e-01 +/- 2.3e-02') $obj->latex(enclose => '$'); # returns '$5.6 \cdot 10^{-1} \pm 2.3 \cdot 10^{-2}$' The asymmetric environment-like C can be used as follows: $obj->latex(enclose => ['\begin{equation}', '\end{equation}']); # returns'\begin{equation}5.6 \cdot 10^{-1} \pm 2.3 \cdot 10^{-2}\end{equation}' There are two convenience methods C and C which do exactly what the above examples demonstrated. The C parameter can set the radix (I) used. The default is a dot (C<.>). If you use a comma, LaTeX will generally typeset it in a way that results in a space after the comma. Since that is not desireable, using a C<,> as the radix results in the radix being set as C<,\!>. An example can be found in the synopsis. =cut our $CFloatCapture = qr/([+-]?)(?=\d|\.\d)(\d*(?:\.\d*)?)((?:[Ee][+-]?\d+)?)/; sub latex { my $self = shift; croak("Uneven number of arguments to ".__PACKAGE__."->latex().") if @_ % 2; my %opt = @_; my $radix = $opt{radix}; if (not defined $radix) { $radix = '.'; } elsif ($radix eq '.') { #fine } else { $radix .= '\!'; } my $enclose = $opt{enclose}; $enclose = '' if not defined $enclose; $enclose = '' if _ARRAY0($enclose) and @$enclose != 2; my $str = "".$self->round(); my $result; pos($str) = 0; my $p = -1; my $number = 1; while (defined pos($str) and pos($str) < length($str)) { die "Failed to advance string parser at position $p in '$str'." if pos($str) == $p; $p = pos($str); # number if ($number) { $str =~ /\G\s*$CFloatCapture\s*/cgo or die "Expected number starting at position $p in '$str'."; my $sgn = $1; my $num = $2; my $exp = $3; unless ($exp =~ s/^[eE]([+-]?)(\d+)$/" \\cdot 10^{".($1eq'-'?'-':'').(0+$2)."}"/e) { $exp = ' \cdot 10^{0}'; } $num =~ s/\./$radix/; $result .= "$sgn$num$exp"; $number = 0; } # +/-, +, - else { $str =~ /\G\s*(\+\/\-|\+|\-)\s*/cgo or die "Expected operator (+/-, +, -) starting at position $p in '$str'."; my $op = $1; if ($op eq '+/-') { $op = '\pm'; } $result .= " $op "; $number = 1; } } if (_ARRAY0($enclose)) { return $enclose->[0].$result.$enclose->[1]; } else { return $enclose.$result.$enclose; } } =head2 latex_math Works exactly like C except that the C string defaults to C<$>. =cut sub latex_math { shift()->latex(enclose => '$', @_) } =head2 latex_equation Works exactly like C except that the C string defaults to the environment C<\begin{equation}\n> and C<\n\end{equation}>. =cut sub latex_equation { shift()->latex(enclose => ["\\begin{equation}\n", "\n\\end{equation}"], @_) } =head2 encode This method encodes an arbitrary UTF-8 string as TeX. Syntax: my $encoded = $obj->encode($string); For detailed documentation, please refer to L. =cut sub encode { my $self = shift; return Encode::encode('latex', shift); } 1; __END__ =pod =head1 SUPPORT Bugs should be reported via the CPAN bug tracker at L For other issues, contact the author. =head1 SEE ALSO It is important that you have a look at the L module if you use the C method. The C operation from that module, however, is not supported by C. You may use L with this module. Also, it should be possible to use L to calculate larger formulas. Just assign a C object to the C variables and it should work. You also possibly want to have a look at the L pragma. The test suite is implemented using the L module. In order to keep the total test time in reasonable bounds, the default number of test attempts to falsify the test properties is kept at a low number of 100. You can enable more rigorous testing by setting the environment variable C to a higher value. A value in the range of C<1500> to C<3000> is probably a good idea, but takes a long time to test. =head1 AUTHOR Steffen Mueller Emodules at steffen-mueller dot netE, L =head1 COPYRIGHT Copyright 2006 Steffen Mueller. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut