diff --git a/MANIFEST b/MANIFEST index 8f7950d32..11f9dd744 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1016,6 +1016,15 @@ t/complex/physics.xml t/complex/si.pdf t/complex/si.tex t/complex/si.xml +t/complex/si_preamble.pdf +t/complex/si_preamble.tex +t/complex/si_preamble.xml +t/complex/siV2.pdf +t/complex/siV2.tex +t/complex/siV2.xml +t/complex/siV3.pdf +t/complex/siV3.tex +t/complex/siV3.xml t/complex/sunset.jpg t/complex/tcilatex_minimal.pdf t/complex/tcilatex_minimal.tex diff --git a/lib/LaTeXML/Package/siunitx.sty.ltxml b/lib/LaTeXML/Package/siunitx.sty.ltxml index b6173b4db..58d676c3e 100644 --- a/lib/LaTeXML/Package/siunitx.sty.ltxml +++ b/lib/LaTeXML/Package/siunitx.sty.ltxml @@ -14,20 +14,137 @@ package LaTeXML::Package::Pool; use strict; use warnings; use LaTeXML::Package; +use LaTeXML::Core::Box; +use Math::Trig qw(:radial :pi deg2rad rad2deg); + +# siunitx version 3 was released in May 2021. I'm not sure which is in GitHub's TeXLive 2021 +my $FMT_YEAR = Expand(T_CS('\fmtversion'))->toString; +$FMT_YEAR =~ s/\D.*//; +my $VERSION_TWO = ( $FMT_YEAR < 2021 ); # or 2022? +# or it was loaded with [=v2] or [=2021-04-09], once issue #2719 is fixed +# differences are tested in v2 and v3 files + +# In fact, the input-separators can only be changed in the package's load phase +my @PREAMBLE_SETTINGS = qw( list-input-separator product-input-separator table-column-type ); + +# A meta setting sets other settings. Look for `.meta:n` in `siunitx.sty` to find them +my %META_SETTING = ( + 'color' => ['number-color', 'unit-color'], + 'digit-group-size' => ['digit-group-first-size', 'digit-group-other-size'], + 'mode' => ['number-mode', 'unit-mode'], + 'per-mode' => ['display-per-mode', 'inline-per-mode'], + 'print-implicit-plus' => ['print-mantissa-implicit-plus', 'print-exponent-implicit-plus'], + 'table-alignment' => ['table-number-alignment', 'table-text-alignment'], + # we also use this for synonym keys + 'add-integer-zero' => ['print-zero-integer'], + 'print-zero-integer' => ['add-integer-zero'], + 'drop-uncertainty' => ['omit-uncertainty'], + 'omit-uncertainty' => ['drop-uncertainty'], + 'bracket-ambiguous-numbers' => ['bracket-numbers'], + 'bracket-numbers' => ['bracket-ambiguous-numbers'], + 'add-arc-degree-zero' => ['fill-angle-degrees'], + 'add-arc-minute-zero' => ['fill-angle-minutes'], + 'add-arc-second-zero' => ['fill-angle-seconds'], + 'fill-angle-degrees' => ['add-arc-degree-zero'], + 'fill-angle-minutes' => ['add-arc-minute-zero'], + 'fill-angle-seconds' => ['add-arc-second-zero'], + 'print-unity-mantissa' => ['retain-unity-mantissa'], + 'retain-unity-mantissa' => ['print-unity-mantissa'], + 'print-zero-exponent' => ['retain-zero-exponent'], + 'retain-zero-exponent' => ['print-zero-exponent'], + 'product-symbol' => ['output-product'], + 'output-product' => ['product-symbol'], + 'quantity-product' => ['number-unit-product'], + 'number-unit-product' => ['quantity-product'], + 'multi-part-units' => ['separate-uncertainty-units'], + 'separate-uncertainty-units' => ['multi-part-units'], + 'table-align-text-before' => ['table-align-text-pre'], + 'table-align-text-pre' => ['table-align-text-before'], + 'table-align-text-after' => ['table-align-text-post'], + 'table-align-text-post' => ['table-align-text-after'], +); + +my %ANTONYM = ( + 'drop-zero-decimal' => 'add-decimal-zero', + 'add-decimal-zero' => 'drop-zero-decimal' +); + +# choice settings only allow a fixed set of options. Look for `.choices:nn` and `.choice:` in `siunitx.sty` +my %CHOICE_SETTING = ( + # These come from .choices:nn + 'display-per-mode' => [ + 'fraction', 'power', 'power-positive-first', 'repeated-symbol', 'symbol', 'single-symbol'], + 'exponent-mode' => ['engineering', 'fixed', 'input', 'scientific', 'threshold'], + 'inline-per-mode' => [ + 'fraction', 'power', 'power-positive-first', 'repeated-symbol', 'symbol', 'single-symbol'], + 'list-exponents' => ['combine', 'combine-bracket', 'individual'], + 'list-units' => ['bracket', 'brackets', 'independent', 'repeat', 'single'], + 'number-mode' => ['match', 'math', 'text'], + 'prefix-mode' => ['combine-exponent', 'extract-exponent', 'input'], + 'product-exponents' => ['combine', 'combine-bracket', 'individual'], + 'product-units' => [ +'bracket', 'brackets', 'bracket-power', 'brackets-power', 'independent', 'power', 'repeat', 'single'], + 'qualifier-mode' => ['bracket', 'brackets', 'combine', 'phrase', 'space', 'subscript', 'text'], + 'range-exponents' => ['combine', 'combine-bracket', 'individual'], + 'range-units' => ['bracket', 'brackets', 'independent', 'repeat', 'single'], + 'round-direction' => ['down', 'nearest', 'up'], + 'round-mode' => ['figures', 'none', 'places', 'uncertainty'], + 'table-alignment-mode' => ['none', 'format', 'marker'], + 'table-number-alignment' => ['center', 'left', 'right'], + 'table-text-alignment' => ['center', 'left', 'right', 'none'], + 'uncertainty-descriptor-mode' => ['bracket', 'bracket-separator', 'separator', 'subscript'], + 'uncertainty-mode' => ['compact', 'compact-marker', 'full', 'separate'], + 'uncertainty-round-direction' => ['down', 'nearest', 'up'], + 'unit-mode' => ['match', 'math', 'text'], + # These come from .choice: (this is also used for deprecated boolean options) + 'angle-mode' => ['arc', 'decimal', 'input'], + 'complex-angle-unit' => ['degrees', 'radians'], + 'complex-mode' => ['cartesian', 'polar', 'input'], + 'complex-root-position' => ['after-number', 'before-number'], + 'compound-boundary-mode' => ['number', 'text'], + 'compound-exponents' => ['combine', 'combine-bracket', 'individual'], + 'compound-separator-mode' => ['number', 'text'], + 'compound-units' => ['bracket', 'bracket-power', 'power', 'repeat', 'single'], + 'group-digits' => ['all', 'decimal', 'integer', 'none', 'true', 'false'], + 'multi-part-units' => ['brackets', 'repeat', 'single', 'true'], # deprecated in v3 + 'product-mode' => ['phrase', 'symbol'], + 'round-half' => ['even', 'up'], + 'separate-uncertainty-units' => ['bracket', 'repeat', 'single'], + 'scientific-notation' => ['engineering', 'fixed', 'false', 'true'] # deprecated in v3 +); + +my %LOCALE = ( + BR => { 'exponent-product' => '\times', 'inter-unit-product' => '\,', 'output-decimal-marker' => '{,}' }, + DE => { 'exponent-product' => '\cdot', 'inter-unit-product' => '\,', 'output-decimal-marker' => '{,}' }, + FR => { 'exponent-product' => '\times', 'inter-unit-product' => '\,', 'output-decimal-marker' => '{,}' }, + IT => { 'exponent-product' => '\times', 'inter-unit-product' => '\,', 'output-decimal-marker' => '{,}' }, + PL => { 'exponent-product' => '\cdot', 'inter-unit-product' => '\cdot', 'output-decimal-marker' => '{,}' }, + SI => { 'exponent-product' => '\times', 'inter-unit-product' => '\,', 'output-decimal-marker' => '{,}' }, + UK => { 'exponent-product' => '\times', 'inter-unit-product' => '\,', 'output-decimal-marker' => '.' }, + US => { 'exponent-product' => '\times', 'inter-unit-product' => '\,', 'output-decimal-marker' => '.' }, + ZA => { 'exponent-product' => '\times', 'inter-unit-product' => '\cdot', 'output-decimal-marker' => '{,}' } +); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #====================================================================== # TODO: -# * rounding options for number formatting # * Semantics! should be possible to directly construct XMDual's for these # without invoking the MathParser at all. -# * table alignments! +# * table alignments? #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #====================================================================== -# recent siunitx have an expectation for latex3 capability. -RequirePackage('expl3'); -# Would be nice if we could load the package (without errors!), + +# Would be nice if we could load the package (without errors!): +# InputDefinitions('siunitx', type=>'sty', noltxml => 1); # in order to pick up all the unit definitions! +# But siunitx runs into many errors, starting with: +# Error:recursion:\q_recursion_stop Token T_CS[\q_recursion_stop] expands into itself! +# at siunitx.sty; line 6587 col 1 - line 6587 col 4 +# defining as empty +# Next token is T_CS[\__siunitx_number_token_auxi:NN] ( == Core::Definition::Expandable[\__siunitx_number_token_auxi:NN {}{}]) +# In Core::Definition::Expandable[\q_recur... latex; from line 1 col 1 to line 1 col 1 +# <= Core::Gullet[@0x13361da10] <= Core::Stomach[@0x132025e10] <= Core::Gullet[@0x13361da10] <= ... + RequirePackage('xcolor'); RequirePackage('amstext'); RequirePackage('array'); @@ -40,51 +157,133 @@ foreach my $key (qw( free-standing-units overwrite-functions bracket-numbers detect-family detect-italic detect-mode detect-shape detect-weight multi-part-units parse-numbers - parse-units product-units + group-four-digits copy-complex-root copy-decimal-marker - bracket-negative-numbers bracket-numbers - separate-uncertainty tight-spacing - retain-explicit-plus add-decimal-zero add-integer-zero + bracket-numbers + separate-uncertainty + retain-explicit-decimal-marker retain-explicit-plus add-decimal-zero add-integer-zero retain-unity-mantissa retain-zero-exponent omit-uncertainty add-arc-degree-zero add-arc-minute-zero add-arc-second-zero angle-symbol-over-decimal - sticky-per prefixes-as-symbols + prefixes-as-symbols + retain-zero-uncertainty retain-negative-zero + + propagate-math-font reset-math-version reset-text-family reset-text-series reset-text-shape text-family-to-math text-series-to-math + evaluate-expression + drop-exponent drop-uncertainty drop-zero-decimal round-pad round-zero-positive + bracket-ambiguous-numbers bracket-negative-numbers print-exponent-implicit-plus print-implicit-plus print-mantissa-implicit-plus + print-unity-mantissa print-zero-exponent print-zero-integer simplify-uncertainty tight-spacing zero-decimal-as-symbol + exponent-to-prefix list-independent-prefix product-independent-prefix range-independent-prefix + print-complex-unity + angle-symbol-over-decimal fill-angle-degrees fill-angle-minutes fill-angle-seconds + free-standing-units overwrite-command space-before-unit unit-optional-argument use-xspace + bracket-unit-denominator forbid-literal-units parse-units power-half-as-sqrt sticky-per + allow-quantity-breaks extract-mass-in-kilograms + table-align-comparator table-align-exponent table-align-text-after table-align-text-before table-align-uncertainty table-auto-round table-fixed-width )) { DefKeyVal('SIX', $key, '', 'true'); } +# despite setting the $default to 'true', siunitx will treat the default as false +# we'll set things to true at the end sub six_get { - my ($key) = @_; - return LookupValue('SIX_' . ToString($key)); } + my (@keys) = @_; + foreach my $key (@keys) { + if (my $v = LookupValue('SIX_' . ToString($key))) { + return $v; } } + return; } # And should probably trim spaces off the values... sub six_getBool { - my ($key) = @_; - my $v = LookupValue('SIX_' . ToString($key)); - return unless defined $v; - $v = ToString($v); $v =~ s/^\s+//; $v =~ s/\s+$//; - return $v eq 'true'; } - -# Should really figure out how Choice keyvals are set up. + my (@keys) = @_; + foreach my $key (@keys) { + my $v = LookupValue('SIX_' . ToString($key)); + if (defined $v) { + $v = ToString($v); $v =~ s/^\s+//; $v =~ s/\s+$//; + return $v eq 'true'; } } + return 0; } # a key / value wasn't found. return false + # (setting keys without values to true happens because of key / value stuff) + +# choice key vals are checked on setting in six_setup sub six_getChoice { - my ($key) = @_; - my $v = LookupValue('SIX_' . ToString($key)); - $v = $v && ToString($v); - $v =~ s/^\s*//; $v =~ s/\s*$//; - return $v; } + my (@keys) = @_; + foreach my $key (@keys) { + if (my $v = LookupValue('SIX_' . ToString($key))) { + $v = $v && ToString($v); + $v =~ s/^\s*//; $v =~ s/\s*$//; + return $v; } } + Fatal('expected', 'keys', undef, "No values found for choices @keys."); + return; } # Various operators, punctuation, etc, are given in text mode. +# even \times? sub six_get_op { - my ($kv, $key) = @_; - my $text = six_get($key); - return I_wrap($kv, ($text ? Tokens(T_CS('\text'), T_BEGIN, $text, T_END) : ())); } + my ($kv, @keys) = @_; + foreach my $key (@keys) { + if (my $text = six_get($key)) { + return I_wrap($kv, Tokens(T_CS('\text'), T_BEGIN, $text, T_END)); } } + return I_wrap($kv, ()); } sub six_setup { my ($kv) = @_; - my $hash = $kv->getKeyVals; - foreach my $key (keys %$hash) { - my $value = $kv->getValue($key); - AssignValue('SIX_' . $key => $value); } + my @keyVals; +# because %META_SETTING (and table-format and group-four-digits) can change other settings (see siunitx#841), +# we can't use the usual $kv->getKeyVals because the hash is randomly ordered + my @orderedKV = $kv->getPairs; + while (@orderedKV) { + my $key = shift(@orderedKV); + my $val = shift(@orderedKV); + push(@keyVals, [$key, $val]); } + foreach my $keyVal (@keyVals) { + my $key = $$keyVal[0]; + next if ((grep { $_ eq $key } @PREAMBLE_SETTINGS) and not LookupValue('inPreamble')); + #my $value = $kv->getValue($key); + my $value = $$keyVal[1]; + if ($key eq 'locale') { + if ($LOCALE{ $value->toString }) { + while (my ($lkey, $lval) = each %{ $LOCALE{ $value->toString } }) { + AssignValue('SIX_' . $lkey => Tokenize($lval)); } } + else { + Error('unexpected', $value, undef, "Key 'siunitx/locale' accepts only a fixed set of choices"); } } + elsif ($key eq 'table-format') { + six_setup_table_format($value); } + else { + if ($key eq 'group-four-digits' && $value->ToString eq 'true') { + $key = 'digit-group-size'; + $value = T_OTHER(4); } + AssignValue('SIX_' . $key => $value); } + if ($META_SETTING{$key}) { + foreach my $subkey (@{ $META_SETTING{$key} }) { + AssignValue('SIX_' . $subkey => $value); } } + if ($ANTONYM{$key}) { + AssignValue('SIX_' . $ANTONYM{$key} => Tokenize($value->ToString eq 'true' ? 'false' : 'true')); } + if ($CHOICE_SETTING{$key}) { + unless (grep { $_ eq $value->toString } @{ $CHOICE_SETTING{$key} }) { + Error('unexpected', $value, undef, "Key 'siunitx/$key' accepts only a fixed set of choices"); } } } + return; } + +# build the table format by decomposing the parsed table-format value +# these were explicit options in v2, but removed for just table-format in v3 +# we'll store the consequences of the table-format key in the keys used in v2 +sub six_setup_table_format { + my ($tokens) = @_; + my @tokens = $tokens->unlist; + my ($pre, $post); + ($pre, @tokens) = six_peel_group(@tokens); + ($post, @tokens) = six_peel_tail_group(@tokens); + AssignValue('SIX_table-space-text-pre' => ($pre || '')); + AssignValue('SIX_table-space-text-post' => ($post || '')); + # set the defaults + AssignValue('SIX_table-comparator' => Tokenize('false')); + AssignValue('SIX_table-sign-exponent' => Tokenize('false')); + AssignValue('SIX_table-figures-exponent' => T_LETTER(0)); + AssignValue('SIX_table-figures-uncertainty' => T_LETTER(0)); + # then parse the format + six_parse_number(undef, Tokens(@tokens), 1); + # setting table-format resets these + AssignValue('SIX_table-alignment-mode' => Tokenize('format')); + AssignValue('SIX_table-number-alignment' => Tokenize('center')); +# AssignValue('SIX_table-number-alignment' => Tokenize('center' . ( $VERSION_TWO ? '-decimal-marker' : '' ) ) ); return; } # These two should be wrapped around macros that process arguments; @@ -108,6 +307,8 @@ sub six_end_processing { DefPrimitive('\sisetup RequiredKeyVals:SIX', sub { six_setup($_[1]); }); DefMacro('\ProvidesExplFile{}{}{}{}', ''); +# without this, we end up in expl syntax for some reason + DefPrimitiveI('\lx@six@initialize', undef, sub { my $pkgoptions = LookupValue('opt@siunitx.sty'); my $setup = $pkgoptions && Tokenize('\sisetup{' . join(',', map { $_ } @$pkgoptions) . '}'); @@ -125,6 +326,28 @@ DefPrimitiveI('\lx@six@initialize', undef, sub { InputDefinitions('siunitx-binary', type => 'cfg', noltxml => 1); } if (six_getBool('free-standing-units')) { six_enableUnitMacros(six_getBool('overwrite-functions')); } + # the table-column-type setting (default S) can be changed in the preamble, + # so we'll read it after that point to actually set up the columns + my $tableColHeaders = six_get('table-column-type')->toString; + foreach my $tableColHeader (split(//, $tableColHeaders)) { + DefColumnType("$tableColHeader OptionalKeyVals:SIX", sub { + my ($gullet, $kv) = @_; + my $align = 'center'; + if ($kv) { + my $mode = ($kv->getValue('table-alignment-mode') || six_get('table-alignment-mode') || '')->ToString; + # this doesn't quite work - might need table-text-alignment or table-alignment + # but we won't know that until we've parsed the cell, at which point it's too late to change the alignment? + if ($mode eq 'format' || $mode eq 'none' || $kv->hasKey('table-number-alignment')) { + $align = ($kv->getValue('table-number-alignment') || six_get('table-number-alignment') || '')->ToString; } + elsif ($mode eq 'marker') { + $align = 'char:' . six_get('output-decimal-marker')->ToString; } } + $LaTeXML::BUILD_TEMPLATE->addColumn( + before => Tokens(T_BEGIN, + T_CS('\lx@si@column@prep'), ($kv ? (T_OTHER('['), $kv->revert(), T_OTHER(']')) : ()), + T_CS('\lx@SI@column@parse')), + align => $align, + after => Tokens(T_CS('\lx@si@column@end'), T_END)); + return; }); } return; }); AtBeginDocument('\lx@six@initialize'); @@ -176,12 +399,9 @@ DefMathI('\SIUnitSymbolMicro', undef, UTF(0xB5)); # input-close-uncertainty, input-comparators, input-complex-roots, # input-decimal-markers, input-digits, input-exponent-markers, # input-open-uncertainty, input-protect-tokens, input-signs, input-uncertainty-signs, -# input-symbols, parse-numbers +# input-symbols, parse-numbers, input-ignore # Also options for multi-part numbers: # input-product, input-quotient - -# Not yet handled: -# input-ignore #====================================================================== # Low-level parsing aids. @@ -197,14 +417,18 @@ sub six_match_keys { my ($tokens, @sixkeys) = @_; # Skip spaces... # Remove & return all tokens matching one of the sets @sixkeys - my @tomatch = (T_SPACE, map { @{ six_get($_) || [] } } @sixkeys); - my @matched = (); + my @tomatch = (map { @{ six_get($_) || [] } } @sixkeys); + my @toignore = (T_SPACE, @{ six_get('input-ignore') || [] }); + my @matched = (); my $t; while (($t = $$tokens[0]) - && grep { scalar(@$tokens) && $t->equals($_) } @tomatch) { + && ((grep { scalar(@$tokens) && $t->toString eq $_->toString } @tomatch) + || (grep { scalar(@$tokens) && $t->toString eq $_->toString } @toignore))) { shift(@$tokens); - push(@matched, $t) unless $t->equals(T_SPACE); - push(@matched, T_SPACE) if $t->getCatcode == CC_CS; } + unless (grep { scalar(@$tokens) && $t->toString eq $_->toString } @toignore) { + # this means that ignore overrides match + push(@matched, $t); + push(@matched, T_SPACE) if $t->getCatcode == CC_CS; } } return (@matched ? Tokens(@matched) : undef); } sub six_match_sign { @@ -213,115 +437,228 @@ sub six_match_sign { # Match (and REMOVE!) leading tokens that fit the pattern of simplenumber sub six_match_simplenumber { - my ($tokens) = @_; - my $sign = six_match_sign($tokens); - my $integer = six_match_keys($tokens, 'input-digits', 'input-symbols'); + my ($tokens, $is_table_formatter) = @_; + my $sign = six_match_sign($tokens); + my $integer = six_match_keys($tokens, 'input-digits', 'input-symbols'); my ($decimal, $fraction); if ($decimal = six_match_keys($tokens, 'input-decimal-markers')) { $fraction = six_match_keys($tokens, 'input-digits', 'input-symbols'); } + if ($is_table_formatter) { + AssignValue('SIX_table-sign-mantissa' => Tokenize($sign ? 'true' : 'false')); + AssignValue('SIX_table-figures-integer' => $integer || Tokenize(0)); + AssignValue('SIX_table-figures-decimal' => $fraction || Tokenize(0)); + return; } return ($sign || $integer || $decimal || $fraction ? { sign => $sign, integer => $integer, decimal => $decimal, fraction => $fraction } : undef); } sub six_match_uncertainnumber { - my ($tokens) = @_; - my $number = six_match_simplenumber($tokens); - my $uncertainty; - if (my $sign = six_match_keys($tokens, 'input-uncertainty-signs')) { - # \pm form ('separate') allows decimal! (ie. has the same point as the main number) + my ($tokens, $is_table_formatter) = @_; + my $number = six_match_simplenumber($tokens, $is_table_formatter); + my (@uncertainties, $uncertaintySign); + while ($uncertaintySign = six_match_keys($tokens, 'input-uncertainty-signs', 'input-open-uncertainty')) { + if (my $whoops = six_match_keys($tokens, 'input-complex-roots')) { + # Whoops, really should be complex!!!! + unshift(@$tokens, map { $_ ? $_->unlist : () } $uncertaintySign, $whoops); + last; } my ($int, $dec, $frac); $int = six_match_keys($tokens, 'input-digits', 'input-symbols'); + if ($is_table_formatter) { + AssignValue('SIX_table-figures-uncertainty' => $int); + return; } if ($dec = six_match_keys($tokens, 'input-decimal-markers')) { $frac = six_match_keys($tokens, 'input-digits', 'input-symbols'); } # Ambiguous: # \pm # is uncertainty unless followed by i, in which case complex! - if (my $whoops = six_match_keys($tokens, 'input-decimal-markers', 'input-complex-roots')) { + if (my $whoops = six_match_keys($tokens, 'input-complex-roots')) { # Whoops, really should be complex!!!! - unshift(@$tokens, map { $_ ? $_->unlist : () } $sign, $int, $dec, $frac, $whoops); } + unshift(@$tokens, map { $_ ? $_->unlist : () } $uncertaintySign, $int, $dec, $frac, $whoops); + last; } + my %uncertainty = (integer => $int, decimal => $dec, fraction => $frac); + if ($uncertaintySign->equals(six_get('input-open-uncertainty'))) { + if (six_match_keys($tokens, 'input-uncertainty-divider')) { + my ($aint, $adec, $afrac); + $aint = six_match_keys($tokens, 'input-digits', 'input-symbols'); + if ($adec = six_match_keys($tokens, 'input-decimal-markers')) { + $afrac = six_match_keys($tokens, 'input-digits', 'input-symbols'); } + %uncertainty = (%uncertainty, ainteger => $aint, adecimal => $adec, afraction => $afrac); } + six_match_keys($tokens, 'input-close-uncertainty'); } else { - $uncertainty = { sign => $sign, integer => $int, decimal => $dec, fraction => $frac }; } } - elsif (six_match_keys($tokens, 'input-open-uncertainty')) { - # Parenthesized ONLY allows digits (ie. in the same positions as the last digits of the number) - $uncertainty = { integer => six_match_keys($tokens, 'input-digits', 'input-symbols') }; - six_match_keys($tokens, 'input-close-uncertainty'); } - return - ($uncertainty ? { operator => 'uncertain', arg1 => $number, arg2 => $uncertainty } : $number); } + $uncertainty{sign} = $uncertaintySign; } + if (!is_explicit_zero(\%uncertainty) || $uncertainty{ainteger} || six_getBool('retain-zero-uncertainty')) { + push(@uncertainties, \%uncertainty); } } + return scalar(@uncertainties) + ? { operator => 'uncertain', arg1 => $number, arg2 => \@uncertainties } + : $number; } # Parse a Complex number, possibly with Exponential (see above) sub six_match_complexnumber { - my ($tokens) = @_; - my $number = six_match_uncertainnumber($tokens); - if (my $i = six_match_keys($tokens, 'input-complex-roots')) { # pure imaginary! - my $sign = $$number{sign}; $$number{sign} = undef; # Make sign "infix" + my ($tokens, $is_table_formatter) = @_; + my $number = six_match_uncertainnumber($tokens, $is_table_formatter); + if (my $i = six_match_keys($tokens, 'input-complex-roots')) { # pure imaginary, make sign "infix" + my $sign = $$number{sign}; + delete $$number{sign}; $number = { operator => 'complex', symbol => $i, sign => $sign, arg2 => $number }; } # Check if followed by a sign, then expect imaginary part elsif (my $sign = six_match_sign($tokens)) { # Imaginary part my ($i, $imag); if ((($i = six_match_keys($tokens, 'input-complex-roots')) - && ($imag = six_match_uncertainnumber($tokens))) + && ($imag = six_match_uncertainnumber($tokens) || { integer => T_OTHER('1') })) # watch for 1+i || (($imag = six_match_uncertainnumber($tokens)) && ($i = six_match_keys($tokens, 'input-complex-roots')))) { - $number = { operator => 'complex', arg1 => $number, symbol => $i, sign => $sign, arg2 => $imag }; } + $$imag{sign} = $sign; + $number = { operator => 'complex', arg1 => $number, symbol => $i, arg2 => $imag }; } else { Error('unexpected', 'sign', undef, "expected to find complex number"); } } + elsif (six_match_keys($tokens, 'complex-angle-separator')) { + my $imag_angle = six_match_uncertainnumber($tokens); + $number = { operator => 'complex', arg1 => $number, arg2 => $imag_angle, input_form => 'polar' }; } return $number; } sub six_match_scinumber { - my ($tokens) = @_; - my $number = six_match_complexnumber($tokens); + my ($tokens, $is_table_formatter) = @_; + my $sign_mantissa = six_match_sign($tokens); + my $number = six_match_complexnumber($tokens, $is_table_formatter); # Now check if followed by exponent if (my $mark = six_match_keys($tokens, 'input-exponent-markers')) { - my $sign = six_match_sign($tokens); - my $exp = six_match_keys($tokens, 'input-digits', 'input-symbols'); + my $sign_exponent = six_match_sign($tokens); + my $exp = six_match_keys($tokens, 'input-digits', 'input-symbols'); + if ($is_table_formatter) { + AssignValue('SIX_table-sign-exponent' => Tokenize($sign_exponent ? 'true' : 'false')); + AssignValue('SIX_table-figures-exponent' => $exp); + return; } $number = { operator => 'exponent', arg1 => $number, - arg2 => { sign => $sign, integer => $exp } }; } + arg2 => { sign => $sign_exponent, integer => $exp } }; } + $$number{sign} = $sign_mantissa if ($sign_mantissa); return $number; } sub six_match_compoundnumber { - my ($tokens) = @_; - if (my $comp = six_match_keys($tokens, 'input-comparators')) { - return { operator => 'comparator', comparator => $comp, arg1 => six_match_number($tokens) }; } + my ($tokens, $is_table_formatter) = @_; + my $comp = six_match_keys($tokens, 'input-comparators'); + if ($is_table_formatter) { + AssignValue('SIX_table-comparator' => Tokenize('true')) if ($comp); + six_match_scinumber($tokens, $is_table_formatter); + return; } + if ($comp) { + return { operator => 'comparator', comparator => $comp, arg1 => six_match_scinumber($tokens) }; } else { my $number = six_match_scinumber($tokens); while (1) { - my $op; - if ($op = six_match_keys($tokens, 'input-product')) { + if (six_match_keys($tokens, 'input-product') || six_match_keys($tokens, 'product-input-separator')) { $number = { operator => 'product', arg1 => $number, arg2 => six_match_scinumber($tokens) }; } - elsif ($op = six_match_keys($tokens, 'input-quotient')) { + elsif (six_match_keys($tokens, 'input-quotient')) { $number = { operator => 'quotient', arg1 => $number, arg2 => six_match_scinumber($tokens) }; } else { return $number; } } - return $number; } } # never gets here... + Fatal('internal', undef, undef, 'This point should not be reached'); + return $number; } } sub six_match_number { - my ($tokens) = @_; - return six_match_compoundnumber($tokens); } + my ($tokens, $is_table_formatter) = @_; + return six_match_compoundnumber($tokens, $is_table_formatter); } #====================================================================== # Post-processing numbers +# round-half, round-minimum, round-mode, round-precision, scientific-notation, zero-decimal-to-integer # Options NOT YET HANDLED: -# fixed-exponent, -# minimum-integer-digits, retain-unity-mantissa -# round-half, round-integer-to-decimal, round-minimum -# round-mode, round-precision, scientific-notation, zero-decimal-to-integer +# round-integer-to-decimal sub six_postprocess { my ($number) = @_; + $number = six_ensure_scientific($number) if (six_getChoice('exponent-mode') ne 'input'); + six_round($number) if six_getBool('parse-numbers'); return six_postprocess_aux($number); } +sub six_ensure_scientific { + my ($number) = @_; + my $op = $$number{operator}; + return $number if ($op && $op eq 'exponent'); + if (!$op || $op eq 'complex' || $op eq 'uncertain') { + return { arg1 => $number, operator => 'exponent', arg2 => { integer => T_OTHER('0') } }; } + else { + $$number{arg1} = six_ensure_scientific($$number{arg1}) if ($$number{arg1}); + $$number{arg2} = six_ensure_scientific($$number{arg2}) if ($$number{arg2}); } + return $number; } + sub six_postprocess_aux { my ($number) = @_; if (!$number) { } elsif (my $op = $$number{operator}) { - $$number{arg1} = six_postprocess_aux($$number{arg1}); - $$number{arg2} = six_postprocess_aux($$number{arg2}); } + if ($op eq 'uncertain') { + if (six_getBool('drop-uncertainty')) { + $$number{sign} ||= $$number{arg1}->{sign}; + $number = $$number{arg1}; } + else { + $$number{arg2} = [map { six_postprocess_aux($_) } @{ $$number{arg2} }]; } } + elsif ($op eq 'exponent') { + my $exponentMode = six_getChoice('exponent-mode'); + if ($exponentMode ne 'input') { + $$number{arg1}->{decimal} ||= six_get('output-decimal-marker'); + my @intTokens = $$number{arg1}->{integer} && $$number{arg1}->{integer}->can('unlist') ? $$number{arg1}->{integer}->unlist : Tokens(); + my @fracTokens = $$number{arg1}->{fraction} && $$number{arg1}->{fraction}->can('unlist') ? $$number{arg1}->{fraction}->unlist : Tokens(); + my $parsedExp = six_UnTeX($$number{arg2}) || 0; + if ($exponentMode eq 'fixed') { + my $fixedExponent = six_get('fixed-exponent')->toString; + $$number{arg1} = six_get_number_with_sci_exp($number, $fixedExponent); + $parsedExp = $fixedExponent; } + else { + # we don't want to use six_get_number_with_sci_exp because that drops the exponent + while (1 < @intTokens && !number_is_zero([@intTokens[0 .. $#intTokens - 1]])) { + unshift(@fracTokens, pop(@intTokens)); + $parsedExp++; } + while (number_is_zero(\@intTokens) && !number_is_zero(\@fracTokens)) { + push(@intTokens, shift(@fracTokens)); + $parsedExp--; } + if ($exponentMode eq 'engineering') { + while ($parsedExp % 3) { + push(@intTokens, (shift(@fracTokens) || T_OTHER('0'))); + $parsedExp--; } } + elsif ($exponentMode eq 'threshold') { + my $tokens = six_get('exponent-thresholds')->clone; + my $lowerThreshold = ToString(six_match_keys($tokens, 'input-digits', 'input-signs')); + six_match_keys($tokens, 'exponent-threshold-separator'); + my $upperThreshold = ToString(six_match_keys($tokens, 'input-digits')); + if ($lowerThreshold < $parsedExp && $parsedExp < $upperThreshold) { + while (0 < $parsedExp) { + push(@intTokens, (shift(@fracTokens) || T_OTHER('0'))); + $parsedExp--; } + while ($parsedExp < 0) { + unshift(@fracTokens, (pop(@intTokens) || T_OTHER('0'))); + $parsedExp++; } } } + $$number{arg1}{integer} = Tokens(@intTokens); + $$number{arg1}{fraction} = Tokens(@fracTokens); + delete $$number{arg1}{decimal} if (!@fracTokens); } + $$number{arg2} = { integer => Tokenize(($parsedExp < 0 ? -1 : 1) * $parsedExp) }; + $$number{arg2}{sign} = T_OTHER('-') if ($parsedExp < 0); } + if (six_getBool('drop-exponent')) { + if ($$number{arg2} && $$number{arg2}{integer}) { + # mimic an siunitx warning + Warn('expected', undef, undef, 'Potentially ambiguous dropping of exponent'); } + $$number{sign} ||= $$number{arg1}->{sign}; + $number = six_postprocess_aux($$number{arg1}); } + $$number{arg2} = six_postprocess_aux($$number{arg2}); } + else { + $$number{arg1} = six_postprocess_aux($$number{arg1}); } } else { if (six_getBool('add-decimal-zero') && $$number{decimal} && !$$number{fraction}) { - $$number{fraction} = T_OTHER('0'); } + $$number{fraction} = Tokenize(0); } if (six_getBool('add-integer-zero') && $$number{decimal} && !$$number{integer}) { - $$number{integer} = T_OTHER('0'); } + $$number{integer} = Tokenize(0); } if (my $s = !$$number{sign} && six_get('explicit-sign')) { $$number{sign} = $s; } } + while ($$number{fraction} && @{ $$number{fraction} } + && $$number{fraction}->[-1]->equals(T_OTHER('0')) && six_getBool('drop-zero-decimal')) { + pop(@{ $$number{fraction} }); } + if ($$number{integer} && $$number{fraction} && number_is_zero(@{ $$number{fraction} }) + && (six_getBool('zero-decimal-to-integer') || six_getBool('drop-zero-decimal'))) { + delete $$number{decimal}; + delete $$number{fraction}; } + $$number{integer} ||= Tokens() if (six_get('minimum-integer-digits')->toString); + $$number{fraction} ||= Tokens() if (six_get('minimum-decimal-digits')->toString); + while ($$number{fraction} && @{ $$number{fraction} } < six_get('minimum-decimal-digits')->toString) { + push(@{ $$number{fraction} }, T_OTHER('0')); } + while ($$number{integer} && @{ $$number{integer} } < six_get('minimum-integer-digits')->toString) { + unshift(@{ $$number{integer} }, T_OTHER('0')); } return $number; } # Given an uncertain number whose uncertainty is not separate (ie. it is relative) @@ -331,24 +668,37 @@ sub six_compute_separate_uncertainty { my $number = $$uncertain{arg1}; my $uncertainty = $$uncertain{arg2}; my $num = $$uncertainty{integer}; + my $anum = $$uncertainty{ainteger}; return $uncertainty if $$uncertainty{sign}; # Has sign? already separate + if ($$uncertainty{decimal}) { # Has decimal? Use that + $$uncertainty{decimal} = six_get('output-decimal-marker'); + $$uncertainty{sign} = T_CS('\pm'); + return $uncertainty; } my @dig = $num->unlist; + my @adig = $anum && $anum->unlist; my $n = scalar(@dig); my $ndigits = ($$number{fraction} ? scalar($$number{fraction}->unlist) : 0); + my %returned = (sign => T_CS('\pm'), decimal => six_get('output-decimal-marker')); if ($n <= $ndigits) { for (my $i = $n ; $i < $ndigits ; $i++) { - unshift(@dig, T_OTHER('0')); } - return { sign => T_CS('\pm'), - integer => T_OTHER('0'), decimal => six_get('output-decimal-marker'), - fraction => Tokens(@dig) }; } + unshift(@dig, T_OTHER('0')); + if ($anum) { + unshift(@adig, T_OTHER('0')); } } + @returned{ 'integer', 'fraction' } = (T_OTHER('0'), Tokens(@dig)); + if ($anum) { + @returned{ 'ainteger', 'afraction' } = (T_OTHER('0'), Tokens(@adig)); } } else { - my @man = (); + my @man = (); + my @aman = (); for (my $i = $n ; $i > $ndigits ; $i--) { - push(@man, shift(@dig)); } - return { sign => T_CS('\pm'), - integer => Tokens(@man), decimal => six_get('output-decimal-marker'), - fraction => Tokens(@dig) }; } } + push(@man, shift(@dig)); + if ($anum) { + push(@aman, shift(@adig)); } } + @returned{ 'integer', 'fraction' } = (Tokens(@man), Tokens(@dig)); + if ($anum) { + @returned{ 'ainteger', 'afraction' } = (Tokens(@aman), Tokens(@adig)); } } + return \%returned; } sub six_compute_relative_uncertainty { my ($uncertain) = @_; @@ -390,42 +740,83 @@ sub six_apply_mathligatures { my $repl; if (@tokens && ($repl = $six_mathligatures{ $t->getCSName }{ $tokens[0]->getCSName })) { shift(@tokens); push(@r, $repl); } - elsif ($t->getCatcode == CC_COMMENT) { } else { push(@r, $t); } } return @r; } +sub six_compute_separate_uncertainties { + my ($number) = @_; + my $arg1 = $$number{arg1}; + my $arg2 = $$number{arg2}; + my @uncertainties; + my $fake_number = { + arg1 => $arg1, + operator => 'uncertain' }; + foreach (@{$arg2}) { + $$fake_number{arg2} = $_; + push(@uncertainties, six_compute_separate_uncertainty($fake_number)); } + return \@uncertainties; } + +sub six_compute_relative_uncertainties { + my ($number) = @_; + my $arg1 = $$number{arg1}; + my $arg2 = $$number{arg2}; + my @uncertainties; + my $fake_number = { + arg1 => $arg1, + operator => 'uncertain' }; + foreach (@{$arg2}) { + $$fake_number{arg2} = $_; + push(@uncertainties, six_compute_relative_uncertainty($fake_number)); } + return \@uncertainties; } + # Note that these 2 will return Tokens if parse-numbers is false!!!! # TODO: Don't signal error if we're doing table columns!? # These extract & REMOVE the number from $expr (Tokens), # NOT reading from $gullet, which is only passed in for error reporting. +# This is also used to parse a table-format sub six_parse_number { - my ($gullet, $expr) = @_; + my ($gullet, $expr, $is_table_formatter) = @_; my $result = $expr; if (six_getBool('parse-numbers')) { my $expanded = Expand($expr); my $tokens = [six_apply_mathligatures($expanded->unlist)]; - $result = six_postprocess(six_match_number($tokens)); + if ($is_table_formatter) { + six_match_number($tokens, $is_table_formatter); + return; } + my $matched = six_match_number($tokens); + if ($$matched{integer} && $$matched{decimal} && !$$matched{fraction} && !six_getBool('retain-explicit-decimal-marker')) { + delete $$matched{decimal}; } + # todo upgrade + if ($$matched{sign} && $$matched{sign}->ToString eq '+' && !six_getBool('retain-explicit-plus')) { + # make sure an explicit-sign doesn't get added later + $$matched{sign} = T_CS('\lx@InvisiblePlus'); } + if ($$matched{sign} && $$matched{sign}->ToString eq '-' && is_explicit_zero($matched) && !six_getBool('retain-negative-zero')) { + delete $$matched{sign}; } + $result = six_postprocess($matched); if (scalar(@$tokens)) { - Error('unexpected', $$tokens[0], $gullet, - "Not matched in \\num: " . ToString(Tokens(@$tokens)) . "\n"); - return $expr; } } + Error('unexpected', $$tokens[0], $gullet, 'Not matched in \num: ' . ToString(Tokens(@$tokens)) . "\n"); + $result = $expr; } } return $result; } sub six_parse_numbers { my ($gullet, $expr) = @_; - my $result = $expr; + # these options are constant: angle doesn't exist, and + # list and product must be set when the package is loaded + my @numberSeparators = ('list-input-separator', + 'angle-input-separator', + 'product-input-separator'); my @results = (); if (six_getBool('parse-numbers')) { my $expanded = Expand($expr); my $tokens = [six_apply_mathligatures($expanded->unlist)]; - while (1) { - $result = six_postprocess(six_match_number($tokens)); - push(@results, $result); - if (@$tokens && $$tokens[0]->equals(T_OTHER(';'))) { - shift(@$tokens); } - else { - last; } } + my $separatorsFound; + do { + push(@results, six_postprocess(six_match_scinumber($tokens))); + $separatorsFound = six_match_keys($tokens, @numberSeparators); + if ($separatorsFound && scalar(@{$separatorsFound}) > 1) { + push(@results, (undef) x (scalar(@{$separatorsFound}) - 1)); } # eg \ang{;;3} + } while ($separatorsFound); if (scalar(@$tokens)) { Error('unexpected', $$tokens[0], $gullet, "Not matched in \\num: " . ToString(Tokens(@$tokens)) . "\n"); @@ -437,10 +828,27 @@ sub six_parse_numbers { my @r = (); while (@tokens && !$tokens[0]->equals(T_OTHER(';'))) { push(@r, shift(@tokens)); } - push(@results, Tokens(@r)); } - } + push(@results, Tokens(@r)); } } return @results; } +sub number_is_zero { + my ($number) = @_; + unless (defined $number) { + return 1; } + if (ref($number) ne 'ARRAY' && $number->equals(T_OTHER('0'))) { + return 1; } + unless (ref($number) eq 'ARRAY' || $number->isa('ARRAY')) { + return 0; } + foreach my $digit (@{$number}) { + unless ((ref($digit) eq 'SCALAR' && $digit == 0) || (ref($digit) eq 'LaTeXML::Core::Token' && $digit->ToString eq '0')) { + return 0; } } + return 1; } + +sub is_explicit_zero { + my ($arg) = @_; + return $arg && !$$arg{operator} && !$$arg{arg1} && !$$arg{arg2} + && number_is_zero($$arg{integer}) && number_is_zero($$arg{fraction}); } + #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Formatting numbers # Options: @@ -450,7 +858,7 @@ sub six_parse_numbers { # output-complex-root, output-decimal-marker, output-exponent-marker, output-open-uncertainty, # separate-uncertainty, uncertainty-separator # Also options for multi-part numbers: -# fraction-function, output-product, output-quatient, quotient-mode +# fraction-function, output-product, output-quotient, quotient-mode # Not handled: # tight-spacing @@ -460,42 +868,82 @@ sub six_parse_numbers { # A Simple Number is a number with (possibly) sign, integer & fraction parts as well as uncertainty # but not exponent, imaginary,.... sub six_format_simplenumber { - my ($number, $bracket) = @_; + my ($number, %flags) = @_; + if (six_getBool('print-zero-exponent') && !$flags{in_sci_number}) { + return six_format_scinumber({ arg1 => $number, arg2 => {}, operator => 'exponent' }, %flags); } # Not ONLY format the number, but arrange for a fork representing the semantics! - my @tokens = (); - my @trailer = (); - my $sign = $$number{sign}; - my $integer = $$number{integer}; - my $fraction = $$number{fraction}; - my $grouping = six_getChoice('group-digits'); - if ($sign) { - - if (ToString($sign) eq '-') { - if (my $c = six_get('negative-color')) { - push(@tokens, T_BEGIN, T_CS('\color'), T_BEGIN, $c->unlist, T_END); - unshift(@trailer, T_END); } - if (six_getBool('bracket-negative-numbers')) { - push(@tokens, six_get('open-bracket')); - unshift(@trailer, six_get('close-bracket')); } + my @tokens = (); + my @trailer = (); + $flags{table_signable} = $flags{in_table_number} && !$flags{in_uncertainty} + && six_getBool('table-sign-' . ($flags{in_exponent} && $flags{in_sci_number} ? 'exponent' : 'mantissa')); + my $sign = $$number{sign}; + my $integer = $$number{integer}; + my $fraction = $$number{fraction}; + my $grouping = six_getChoice('group-digits'); + my $needs_sign_space = 0; + + push @tokens, $sign if ($sign && $flags{in_exponent}); + if ($integer) { + my @intTokens = $integer->unlist; + while (@intTokens && $intTokens[0]->equals(T_OTHER('0')) && six_get('minimum-integer-digits')->ToString < @intTokens) { + shift(@intTokens); } + if (!@intTokens && six_getBool('print-zero-integer')) { + unshift(@intTokens, T_OTHER('0')); } + $integer = Tokens(@intTokens); + if (($grouping eq 'all') || ($grouping eq 'true') || ($grouping eq 'integer')) { + $integer = six_groupdigits($integer, +1); } } + elsif (six_getBool('print-zero-integer')) { + $integer = Tokens(T_OTHER('0')); } + if ($flags{in_table_number} && !$flags{in_uncertainty}) { + my $type = $flags{in_exponent} && $flags{in_sci_number} ? 'exponent' : 'integer'; + my $digits_needed = six_get("table-figures-$type")->toString; + my $digits_have = ($integer && @{$integer}) || 0; + if ($digits_have < $digits_needed) { + if ($type eq 'exponent') { + ${ $flags{pad_right_ref} } .= '2' x ($digits_needed - $digits_have); } + elsif ($type eq 'integer') { + ${ $flags{pad_left_ref} } .= '2' x ($digits_needed - $digits_have); } } + if ($needs_sign_space && $type ne 'uncertainty') { + if ($flags{in_exponent}) { + ${ $flags{pad_right_ref} } .= '.'; } # exponentiated + else { - push(@tokens, $sign); } } - elsif ((ToString($sign) eq '+') && !six_getBool('retain-explicit-plus')) { } - else { - push(@tokens, $sign); } } + ${ $flags{pad_left_ref} } .= '2'; } } } # mantissa + if ($integer) { - my $i = (($grouping eq 'true') || ($grouping eq 'integer') - ? six_groupdigits($integer, +1) - : $integer); - push(@tokens, $i); } - if (my $d = (six_getBool('copy-decimal-marker') - ? $$number{decimal} - : ($fraction || $$number{decimal} ? six_get('output-decimal-marker') : undef))) { - push(@tokens, $d); } + push(@tokens, $integer); } + my $decimal = six_getBool('copy-decimal-marker') + ? $$number{decimal} + : (($fraction && @{$fraction}) || ($$number{decimal} && $VERSION_TWO) ? six_get('output-decimal-marker') : undef); + if ($decimal) { + push(@tokens, $decimal); } + my $using_symbol_for_zero; + if ($fraction) { + my @fracTokens = $fraction ? $fraction->unlist : (); + if (number_is_zero($fraction)) { + if (six_getBool('zero-decimal-as-symbol')) { + $using_symbol_for_zero = 1; + $fraction = six_get('zero-symbol'); } + elsif (@fracTokens) { + $fraction = Tokens(@fracTokens); + $fraction = (($grouping eq 'all') || ($grouping eq 'true') || ($grouping eq 'decimal') + ? six_groupdigits($fraction, -1) + : $fraction); } } + else { + $fraction = Tokens(@fracTokens); + $fraction = (($grouping eq 'all') || ($grouping eq 'true') || ($grouping eq 'decimal') + ? six_groupdigits($fraction, -1) + : $fraction); } } + elsif (six_getBool('zero-decimal-as-symbol')) { + $using_symbol_for_zero = 1; + $fraction = six_get('zero-symbol'); } + if ($flags{in_table_number} && !$flags{in_uncertainty} && !$flags{in_exponent}) { + my $digits_needed = six_get('table-figures-decimal')->toString; + ${ $flags{pad_right_ref} } .= '.' if ($digits_needed && !$fraction && !$$number{decimal}); + $fraction = Tokens() if ($digits_needed && !$fraction); + ${ $flags{pad_right_ref} } .= '2' x ($digits_needed - @{$fraction}) if (@{$fraction} < $digits_needed); } if ($fraction) { - my $f = (($grouping eq 'true') || ($grouping eq 'decimal') - ? six_groupdigits($fraction, -1) - : $fraction); - push(@tokens, $f); } + push(@tokens, $fraction); } + # if ( $flags{in_table_number} ) { + # return Tokens(@tokens, @trailer); } return I_dual({ revert_as => 'presentation' }, I_symbol({ role => 'NUMBER', meaning => six_number_string($number) }), I_wrap({}, Tokens(@tokens, @trailer))); } @@ -505,128 +953,468 @@ sub six_groupdigits { my @digs = $digits->unlist; my $min = ToString(six_get('group-minimum-digits')); return $digits if $min > scalar(@digs); - my @r = (); - my $g = 3; - my $sep = six_get('group-separator'); - if ($direction > 0) { + my @r = (); + my $g_first = ToString(six_get('digit-group-first-size')); + my $g_other = ToString(six_get('digit-group-other-size')); + my $sep = six_get('group-separator'); + if ($direction > 0) { + for (my $i = 0 ; @digs && $i < $g_first ; $i++) { unshift(@r, pop(@digs)); } + unshift(@r, $sep) if @digs; while (@digs) { - for (my $i = 0 ; @digs && $i < $g ; $i++) { unshift(@r, pop(@digs)); } + for (my $i = 0 ; @digs && $i < $g_other ; $i++) { unshift(@r, pop(@digs)); } unshift(@r, $sep) if @digs; } } else { + for (my $i = 0 ; @digs && $i < $g_first ; $i++) { push(@r, shift(@digs)); } + push(@r, $sep) if @digs; while (@digs) { - for (my $i = 0 ; @digs && $i < $g ; $i++) { push(@r, shift(@digs)); } + for (my $i = 0 ; @digs && $i < $g_other ; $i++) { push(@r, shift(@digs)); } push(@r, $sep) if @digs; } } return Tokens(@r); } +# rounding has been surprisingly annoying with its edge cases +sub six_round { + my ($number) = @_; + my $mode = six_getChoice('round-mode'); + return if (is_explicit_zero($number) || $mode eq 'none'); + my $op = $$number{operator}; + if ((!!($op) && $op eq 'uncertain') != ($mode eq 'uncertainty')) { + return; } + if ($op) { + if ($op eq 'uncertain') { + six_round_uncertain_number($number); } + elsif ($op eq 'complex' || $op eq 'product' || $op eq 'quotient') { + six_round($$number{arg1}); + six_round($$number{arg2}); } + elsif ($op eq 'comparator' || $op eq 'exponent') { + six_round($$number{arg1}); } + else { + Error('operator', 'operator', undef, "unknown operator: $op"); } } + else { + my $precision = six_get('round-precision')->toString; + shift(@{ $$number{integer} }) while ($$number{integer} && scalar(@{ $$number{integer} }) && $$number{integer}[0]->ToString eq '0'); + if ($mode eq 'figures') { + my $excess_zeros = 0; + if (number_is_zero($$number{integer})) { + foreach my $digit (@{ $$number{fraction} }) { + if ($digit->ToString eq '0') { + $excess_zeros++; } + else { + last; } } } + six_round_simple_number($number, $precision + $excess_zeros, 0); } + elsif ($mode eq 'places') { + six_round_simple_number($number, $precision + scalar(@{ $$number{integer} || [] }), 0); } + else { + Fatal('internal', 'unreachable', undef, 'this code should not have been reached'); } } + return; } + +sub six_round_uncertain_number { + my ($number) = @_; + my $precision = six_get('round-precision')->toString; + shift(@{ $$number{arg2}[0]{integer} }) while (scalar(@{ $$number{arg2}[0]{integer} }) && $$number{arg2}[0]{integer}[0]->equals(T_OTHER(0))); + my $digits_lost = six_round_simple_number($$number{arg2}[0], $precision, 1); + for (1 .. $#{ $$number{arg2} }) { + shift(@{ $$number{arg2}[$_]{integer} }) while (scalar(@{ $$number{arg2}[$_]{integer} }) && $$number{arg2}[$_]{integer}[-1]->equals(T_OTHER(0))); + six_round_simple_number($$number{arg2}[$_], $precision, 1); } + my $new_precision = scalar(@{ $$number{arg1}{integer} || [] }) + scalar(@{ $$number{arg1}{fraction} || [] }) - $digits_lost; + my $added_zeros = six_round_simple_number($$number{arg1}, $new_precision, 0); + if ($added_zeros && !($$number{arg1}{fraction} && scalar(@{ $$number{arg1}{fraction} }))) { + foreach my $uncert (@{ $$number{arg2} }) { + if (!defined $$uncert{fraction}) { + push(@{ $$uncert{integer} }, T_OTHER(0)) for (1 .. $added_zeros); } } } + return; } + +# uncertain numbers are rounded in two stages: first the uncertainty, then the number +# each stage can affect the other part, so we return the necessary information: +# when rounding the uncertainty, how many digits were truncated away +# when rounding the main number, how many zeros pad the integer part +sub six_round_simple_number { + my ($number, $figures, $is_uncertainty) = @_; + my ($stolen_from_integer, $fraction_size) = (0, 0); + my @dropped; + if ($figures <= scalar(@{ $$number{integer} || [] })) { + $stolen_from_integer = scalar(@{ $$number{integer} || [] }) - $figures; + @dropped = splice(@{ $$number{integer} }, $figures); + push(@dropped, @{ $$number{fraction} }) if (scalar(@{ $$number{fraction} || [] })); + $fraction_size = scalar(@{ $$number{fraction} || [] }); + delete $$number{decimal}; + delete $$number{fraction}; } + else { + @dropped = splice(@{ $$number{fraction} }, $figures - scalar(@{ $$number{integer} || [] })); + $fraction_size = scalar(@{ $$number{fraction} }); } + my $round_direction = $is_uncertainty ? six_getChoice('uncertainty-round-direction', 'round-direction') : six_getChoice('round-direction'); + unless (number_is_zero(Tokens(@dropped)) || $round_direction eq 'down') { + my $round_up = $round_direction eq 'up'; + my $first_dropped = shift(@dropped)->toString; + $round_up ||= (5 < $first_dropped || (5 == $first_dropped && !number_is_zero(Tokens(@dropped)))); + if (5 == $first_dropped && number_is_zero(Tokens(@dropped))) { + $round_up ||= six_getChoice('round-half') eq 'up'; + my $remaining = scalar(@{ $$number{fraction} || [] }) ? $$number{fraction}[-1]->toString + : (scalar(@{ $$number{integer} || [] }) ? $$number{integer}[-1]->toString : 0); + $round_up ||= $remaining % 2; } # round-half eq 'even' + if ($round_up && round_last_digit_up($number)) { + # we added an extra figure at the beginning of {integer}. to compensate, drop one at the end + if (scalar(@{ $$number{fraction} || [] })) { + pop(@{ $$number{fraction} }); } + else { + if ($is_uncertainty) { + $stolen_from_integer += $#{ $$number{integer} }; + $$number{integer} = Tokenize(1); } } } } + unless ($is_uncertainty) { + push(@{ $$number{integer} }, Token(0)) for (1 .. $stolen_from_integer); } + if (six_getBool('round-pad') && !$is_uncertainty) { + push(@{ $$number{fraction} }, T_OTHER(0)) while (scalar(@{ $$number{integer} || [] }) + scalar(@{ $$number{fraction} || [] }) < $figures); + $$number{fraction} = Tokens(@{ $$number{fraction} || [] }); } + if (!$is_uncertainty && is_explicit_zero($number)) { + if (my $round_min = six_get('round-minimum')->toString) { + $$number{arg1} = six_parse_number(undef, Tokenize($round_min)); + if ($$number{sign}) { + $$number{arg1}{sign} = $$number{sign}; } + $$number{comparator} = ($$number{sign} && $$number{sign}->toString eq '-') ? Tokenize('>') : Tokenize('<'); + delete $$number{$_} foreach (qw(sign integer decimal fraction)); + $$number{operator} = 'comparator'; } + elsif (six_getBool('round-zero-positive')) { + delete $$number{sign}; } + elsif ($$number{sign} && ToString($$number{sign}) eq '-') { + $$number{rounded_negative} = 1; } } + return ($is_uncertainty ? $fraction_size : 0) + $stolen_from_integer; } + +# returns that a leading 9 was rounded up to 10 +sub round_last_digit_up { + my ($number) = @_; + my $i = $#{ $$number{fraction} }; # this instantiates {frac} as [] if it wasn't there already + while (0 <= $i) { + my $digit = ($$number{fraction}[$i]->toString + 1) % 10; + $$number{fraction}[$i] = Token($digit); + if ($digit) { + $$number{fraction} = Tokens($$number{fraction}); + return 0; } + $i--; } + if (scalar(@{ $$number{fraction} })) { + $$number{fraction} = Tokens($$number{fraction}); } + else { + delete $$number{fraction}; } + $i = $#{ $$number{integer} }; + while (0 <= $i) { + my $digit = ($$number{integer}[$i]->toString + 1) % 10; + $$number{integer}[$i] = Token($digit); + if ($digit) { + $$number{integer} = Tokens($$number{integer}); + return 0; } + $i--; } + unshift(@{ $$number{integer} }, Token(1)); + $$number{integer} = Tokens($$number{integer}); + return 1; } + sub show_thing { my ($thing) = @_; return (ref $thing eq 'HASH' ? '{' . join(',', map { $_ . '=' . show_thing($$thing{$_}); } grep { defined $$thing{$_}; } sort keys %$thing) . '}' - : ToString($thing)); } + : (ref $thing eq 'ARRAY' + ? '[' . join(',', map { show_thing($_) } @$thing) . ']' + : ToString($thing))); } + +# or maybe six_number_string +sub six_UnTeX { + my ($number) = @_; + my $op = $$number{operator}; + if ($op && $op eq 'comparator') { + return UnTeX($$number{comparator}) . six_UnTeX($$number{arg1}); } + if ($op && $op eq 'exponent') { + return six_UnTeX($$number{arg1}) . 'e' . six_UnTeX($$number{arg2}); } + if ($op && $op eq 'uncertain') { + return six_UnTeX($$number{arg1}) . join('', map { '(' . six_UnTeX($_) . ')' } @{ $$number{arg2} }); +#return six_UnTeX($$number{arg1}) . '(' . join( ')(', map(&six_UnTeX, @{$$number{arg2}}) ) . ')'; # deep recursion ? + } + return ($$number{sign} ? UnTeX($$number{sign}) : '') + . ($$number{integer} ? UnTeX($$number{integer}) : '') + . ($$number{decimal} ? UnTeX($$number{decimal}) : ($$number{fraction} ? '.' : '')) + . ($$number{fraction} ? UnTeX($$number{fraction}) : ''); } + +# six_format_simplenumber looks at if ( ToString($sign) eq '+' ) +# to determine if an implicit plus should be dropped +# because ToString(T_CS('\lx@explicit@plus')) eq '\lx@explicit@plus' ne '+', +# that test fails and the sign is printed +DefMacroI('\lx@explicit@plus', undef, '+'); + +sub six_format_asymmetric_uncertainnumber { + my ($number, %flags) = @_; + my $arg1 = $$number{arg1}; + my $arg2 = $$number{arg2}; + my @meaning_args = ({}, I_symbol({ meaning => 'uncertain' }), I_arg(1)); + my @display_args = ({}, ($flags{bracket} ? six_get('open-bracket') : ()), I_arg(1)); + my $counter = 1; + my @used_args = (six_format_number($arg1)); + my $seps = six_compute_separate_uncertainties($number); + + foreach my $sep (@{$seps}) { + if (($$sep{ainteger} || $$sep{afraction}) + && (!six_getBool('simplify-uncertainty') + || (defined $$sep{integer} xor defined $$sep{ainteger}) + || (defined $$sep{fraction} xor defined $$sep{afraction}) + || ($$sep{integer} && ToString($$sep{integer}) ne ToString($$sep{ainteger})) + || ($$sep{fraction} && ToString($$sep{fraction}) ne ToString($$sep{afraction})))) { + push(@meaning_args, I_arg(++$counter), I_arg($counter + 1)); + push(@display_args, T_SUPER, T_BEGIN, I_arg($counter), T_END, T_SUB, T_BEGIN, I_arg(++$counter), T_END); + push(@used_args, + six_format_number({ sign => T_CS('\lx@explicit@plus'), integer => $$sep{integer}, decimal => $$sep{decimal}, fraction => $$sep{fraction} }), + six_format_number({ sign => T_OTHER('-'), integer => $$sep{ainteger}, decimal => $$sep{decimal}, fraction => $$sep{afraction} })); } + else { + $$sep{sign} = T_CS('\pm'); + push(@meaning_args, I_arg(++$counter)); + push(@display_args, I_arg($counter)); + push(@used_args, six_format_number($sep)); } } + push(@display_args, ($flags{bracket} ? six_get('close-bracket') : ())); + return I_dual({ revert_as => 'presentation' }, I_apply(@meaning_args), I_wrap(@display_args), @used_args); } sub six_format_uncertainnumber { - my ($number, $bracket) = @_; + my ($number, %flags) = @_; + my $op = $$number{operator}; my $arg1 = $$number{arg1}; my $arg2 = $$number{arg2}; - return six_format_number($arg1) if !$arg2 || six_getBool('omit-uncertainty'); - my $sep = six_compute_separate_uncertainty($number); - if (six_getBool('separate-uncertainty')) { - my $sign = $$sep{sign}; - $$sep{sign} = undef; - return I_dual({ revert_as => 'presentation' }, - I_apply({}, I_symbol({ meaning => 'uncertain' }), I_arg(1), I_arg(2)), - I_wrap({}, - ($bracket > 0 ? six_get('open-bracket') : ()), - I_arg(1), (six_get('uncertainty-separator') || ()), ($sign || ()), I_arg(2), - ($bracket > 0 ? six_get('close-bracket') : ())), - six_format_number($arg1), six_format_number($sep)); } + $flags{table_uncertain_checked} = 1; + if ($flags{in_table_number} && (!$op || $op ne 'uncertain')) { + ${ $flags{pad_right_ref} } .= ('2' x (1 + six_get('table-figures-uncertainty')->ToString)); # () is about the same width as + + return I_wrap(undef, six_format_number($number, %flags)); } + return six_format_number($arg1, %flags) if (!scalar(@{$arg2})); + my $uncertainty_mode = six_getChoice('uncertainty-mode'); + $uncertainty_mode = 'separate' if (six_getBool('separate-uncertainty')); + $flags{bracket} ||= $flags{in_sci_number} && six_getBool('bracket-ambiguous-numbers') && $uncertainty_mode eq 'separate'; + foreach my $uncertainty (@{$arg2}) { + if ($$uncertainty{ainteger} || $$uncertainty{afraction}) { + return six_format_asymmetric_uncertainnumber($number, %flags); } } + my $seps = six_compute_separate_uncertainties($number); + my $rels; + $rels = six_compute_relative_uncertainties($number) if $uncertainty_mode ne 'separate'; # detects sign, MODIFIES number!!! # todo upgrdae remove conditional + my @meaning_args = map { I_arg($_) } (1 .. scalar(@{$seps}) + 1); + my @dual_args = ({ revert_as => 'presentation' }, + I_apply({}, I_symbol({ meaning => 'uncertain' }), @meaning_args)); + if ($uncertainty_mode eq 'separate' || scalar(@{$seps}) > 1) { + # this does not get descriptors into the meaning + my @descriptors = six_get('uncertainty-descriptors') && split /\s*,\s*/, six_get('uncertainty-descriptors')->toString; + my $descriptorMode = six_getChoice('uncertainty-descriptor-mode'); + my @wrap_args = ({}, ($flags{bracket} ? six_get('open-bracket') : ()), I_arg(1)); + foreach my $i (0 .. $#{$seps}) { + my $sign = $$seps[$i]{sign}; + delete $$seps[$i]{sign}; + push(@wrap_args, (six_get('uncertainty-separator') || ()), ($sign || ()), I_arg(2 + $i)); + if (1 < scalar(@descriptors) && $i < scalar(@descriptors) && 1 < scalar(@{$seps})) { + push(@wrap_args, six_get('uncertainty-descriptor-separator')) if ($descriptorMode =~ /separator$/); + my $text = $descriptors[$i]; + $text = "($text)" if ($descriptorMode =~ /^bracket/); + $text = "_{$text}" if ($descriptorMode eq 'subscript'); + push(@wrap_args, Tokenize($text)); } } + push(@wrap_args, ($flags{bracket} ? six_get('close-bracket') : ())); + my $formatted = six_format_number($arg1, %flags, bracket => 0); + if ($flags{in_table_number} && six_getBool('table-align-uncertainty') && ${ $flags{pad_right_ref} }) { + push(@{$formatted}, six_table_space(${ $flags{pad_right_ref} })); + ${ $flags{pad_right_ref} } = ''; } + push(@dual_args, I_wrap(@wrap_args), $formatted); + foreach (@{$seps}) { + push(@dual_args, six_format_number($_, %flags, bracket => 0)); } + return I_dual(@dual_args); } else { - my $rel = six_compute_relative_uncertainty($number); # detects sign, MODIFIES number!!! - $$sep{sign} = undef; # AFTER computing relative!!! - return I_dual({ revert_as => 'presentation' }, - I_apply({}, I_symbol({ meaning => 'uncertain' }), I_arg(1), I_arg(2)), - I_wrap({}, I_arg(1), (six_get('uncertainty-separator') || ()), I_arg(2)), - six_format_number($arg1), - I_wrap({ meaning => six_number_string($sep) }, - six_get('output-open-uncertainty'), six_format_number($rel), - six_get('output-close-uncertainty'))); } } +# exactly one symmetric uncertainty in parentheses. but just in case, this works for several symmetric uncertainties + my @wrap_args = ({}, ($flags{bracket} ? Tokens(six_get('uncertainty-separator'), six_get('open-bracket')) : ()), I_arg(1)); + my @dual_tail_args; + for my $i (0 .. $#{$seps}) { + push(@wrap_args, (six_get('uncertainty-separator') || ()), I_arg(2 + $i)); + my $sep = $$seps[$i]; + my $rel = $$rels[$i]; + delete $$sep{sign}; # AFTER computing relative!!! + my $uncert = $uncertainty_mode eq 'compact' + || ($uncertainty_mode eq 'compact-marker' + && (number_is_zero($$sep{integer}) || number_is_zero($$sep{fraction}))) ? $rel : $sep; + if ($flags{in_table_number}) { + my $need_digits = six_get('table-figures-uncertainty')->ToString; + ${ $flags{pad_right_ref} } .= '2' x ($need_digits - @{ $$uncert{integer} }) if (@{ $$uncert{integer} } < $need_digits); } + push(@dual_tail_args, + I_wrap({ meaning => six_number_string($sep) }, + six_get('output-open-uncertainty'), six_format_number($uncert, %flags, in_uncertainty => 1, bracket => 0), + six_get('output-close-uncertainty'))); } + push(@wrap_args, ($flags{bracket} ? six_get('close-bracket') : ())); + push(@dual_args, I_wrap(@wrap_args), six_format_number($arg1, %flags, bracket => 0), @dual_tail_args); + return I_dual(@dual_args); } } sub six_format_complexnumber { - my ($number, $bracket) = @_; - my $arg1 = $$number{arg1}; - my $arg2 = $$number{arg2}; - my $real = six_format_number($arg1); - my $imag = six_format_number($arg2); + my ($number, %flags) = @_; + my $arg1 = $$number{arg1}; + my $arg2 = $$number{arg2}; + my $complexMode = six_getChoice('complex-mode'); + # we may run into problems that the input was rounded before it got to this point + if (exists $$number{input_form} && $$number{input_form} eq 'polar' && $complexMode eq 'cartesian') { + my $parsedArg1 = six_UnTeX($arg1) || 0; + my $parsedArg2 = six_UnTeX($arg2) || 0; + if (six_getChoice('complex-angle-unit') eq 'degrees') { + $parsedArg2 %= 360; + $parsedArg2 = deg2rad($parsedArg2); } + ($parsedArg1, $parsedArg2) = $parsedArg2 == pi ? (-$parsedArg1, 0) : cylindrical_to_cartesian($parsedArg1, $parsedArg2); + # or within epsilon of pi? + $arg1 = $parsedArg1 ? six_parse_number(undef, Tokenize($parsedArg1)) : undef; + $arg2 = $parsedArg2 ? six_parse_number(undef, Tokenize($parsedArg2)) : undef; + six_round($arg1); + six_round($arg2); +# $$number{sign} ||= $arg2 && ($$arg2{sign} || ($$arg2{operator} && $$arg2{operator} eq 'exponent' && $$arg2{arg1} && $$arg2{arg1}{sign})) +# ? undef : T_OTHER('+'); + $$number{sign} ||= ($arg2 && $$arg2{sign}) || T_OTHER('+'); } + elsif ((!exists $$number{input_form}) && $complexMode eq 'polar') { + my $parsedArg1 = six_UnTeX($arg1) || 0; + my $parsedArg2 = six_UnTeX($arg2) || 0; + if ($parsedArg1 == 0 && $parsedArg2 == 0 && $$number{operator} eq 'complex' && $$number{symbol}->ToString eq 'i') { + $parsedArg2 = 1; # seems to be a one off case + $$number{sign} ||= T_OTHER('+'); } + ($parsedArg1, $parsedArg2) = cartesian_to_cylindrical($parsedArg1, $parsedArg2); + if (six_getChoice('complex-angle-unit') eq 'degrees') { + $parsedArg2 = rad2deg($parsedArg2); } + $arg1 = six_parse_number(undef, Tokenize($parsedArg1)); + $arg2 = six_parse_number(undef, Tokenize($parsedArg2)); + six_round($arg1); + six_round($arg2); } + my $real = six_format_number($arg1, %flags, bracket => 0, in_sci_number => 0); # toggle off in_sci_number b/c it's already bracketed return $real unless $arg2; - my $i = (six_getBool('copy-complex-root') ? $$number{symbol} : six_get('output-complex-root')); - $i = I_wrap({ role => 'ID', meaning => 'imaginary-unit' }, - Tokens(T_CS('\text'), T_BEGIN, $i, T_END)); - my $result = six_format_infix(T_CS('\lx@InvisibleTimes'), undef, undef, - (six_getChoice('complex-root-position') eq 'before-number' ? ($i, $imag) : ($imag, $i))); - if (!$arg1) { # Force sign on pure imaginary? - if ((ToString($$number{sign}) eq '+') && six_getBool('retain-explicit-plus')) { - $result = I_wrap({}, $$number{sign}, $result); } } - else { - $result = six_format_infix( - $$number{sign}, # Hopefully has proper semantics? - ($bracket > 0 ? six_get('open-bracket') : undef), - ($bracket > 0 ? six_get('close-bracket') : undef), - $real, $result); } - return $result; } + if ($complexMode eq 'cartesian' || ($complexMode eq 'input' && !exists $$number{input_form})) { # Cartesian output + if (six_getBool('print-complex-unity') && !defined $$arg2{integer} && !defined $$arg2{fraction}) { + $$arg2{integer} = T_OTHER(1); } + if (!six_getBool('print-complex-unity') && $$arg2{integer} && number_is_zero($$arg2{fraction}) + && ($$arg2{integer}->ToString eq '1')) { + $arg2 = undef; } + my $sign = $$arg2{sign} || ($arg1 && T_OTHER('+')); + delete $$arg2{sign} if $$arg2{sign}; + my $imag = %$arg2 ? six_format_number($arg2, %flags, bracket => 0, in_sci_number => 0) : (); # toggle off in_sci_number b/c it's already bracketed + my $i = (six_getBool('copy-complex-root') ? $$number{symbol} : six_get('output-complex-root')); + $i = I_wrap({ role => 'ID', meaning => 'imaginary-unit' }, Invocation(T_CS('\text'), $i)); + my $result = six_format_infix(T_CS('\lx@InvisibleTimes'), undef, undef, + (six_getChoice('complex-root-position') eq 'before-number' ? ($i, $imag) : ($imag, $i))); + $flags{bracket} ||= $flags{in_sci_number} && six_getBool('bracket-ambiguous-numbers'); + if ($arg1 && keys %$arg1) { + $result = six_format_infix( + $sign, # Hopefully has proper semantics? + ($flags{bracket} ? six_get('open-bracket') : undef), + ($flags{bracket} ? six_get('close-bracket') : undef), + $real, $result); } + else { # Force sign on pure imaginary? + if ((ToString($sign) eq '+') && six_getBool('retain-explicit-plus')) { + $result = I_wrap({}, $sign, $result); } + if ($flags{bracket}) { + $result = I_wrap({}, six_get('open-bracket'), $sign || (), $result, six_get('close-bracket')); } } + return $result; } + else { # polar output + my $imag = six_format_number($arg2, %flags, bracket => 0); + my $angleMark = six_get('complex-phase-command'); + my $degreeMark = six_get('complex-symbol-degree'); + my $result = six_getChoice('complex-angle-unit') eq 'degrees' ? + six_format_infix(T_CS('\lx@InvisibleTimes'), undef, undef, $imag, $degreeMark) : + $imag; + # there should be a better way to do this. but we have + # $real $angleMark $$number{sign} $imag + # with both middle terms being an infix? + if ($$number{sign} && ($$number{sign}->toString ne '+' || six_getBool('retain-explicit-plus'))) { + $result = six_format_infix(undef, undef, undef, $$number{sign}, $result); } + $result = six_format_infix($angleMark, undef, undef, $real, $result); + return $result; } } sub six_format_scinumber { - my ($number, $bracket) = @_; + my ($number, %flags) = @_; + my $op = $$number{operator}; my $arg1 = $$number{arg1}; my $arg2 = $$number{arg2}; + $flags{table_exponent_checked} = 1; my $result; - # NOTE: Not yet handled: retain-unity-mantissa - if (!six_getBool('retain-zero-exponent') - && !ToString($$arg2{integer}) - && !ToString($$arg2{fraction})) { - $result = six_format_number($arg1); } + if ($flags{in_table_number} && (!$op || $op ne 'exponent')) { + # there's no exponent, but we want space for one. omitting the mathord causes extra space + ${ $flags{pad_right_ref} } .= '222' . ('.' x six_get('table-figures-exponent')->ToString); # \mathord x10^{...} + return I_wrap(undef, six_format_number($number, %flags)); } + if (!six_getBool('print-zero-exponent') && !ToString($$arg2{integer}) && !ToString($$arg2{fraction})) { + # there is no arg2. add padding for \times10^{...} + ${ $flags{pad_right_ref} } .= '222' . ('.' x six_get('table-figures-exponent')->ToString) if $flags{in_table_number}; + $result = six_format_number($arg1, %flags, in_sci_number => 1); } elsif (my $marker = six_get('output-exponent-marker')) { - $result = six_format_infix( - T_CS('\lx@InvisibleTimes'), - ($bracket > 1 ? six_get('open-bracket') : undef), - ($bracket > 1 ? six_get('close-bracket') : undef), - six_format_number($arg1, 1), - I_dual({}, # Means base^arg2, but looks like marker arg2 !! +# the order of the conditionals is important here - $$arg1{integer} causes an $arg1 undef to become {} which is true + if ((six_getBool('print-unity-mantissa') && $arg1) + || ($$arg1{integer} && ToString($$arg1{integer}) ne '1') + || $$arg1{fraction} || $$arg1{operator}) { + my $mantissa = six_format_number($arg1, %flags, in_sci_number => 1); # , bracket => 0 todo upgrade do not need + if ($flags{in_table_number} && six_getBool('table-align-exponent')) { + push(@{$mantissa}, six_table_space(${ $flags{pad_right_ref} })); + ${ $flags{pad_right_ref} } = ''; } + $result = six_format_infix( + T_CS('\lx@InvisibleTimes'), + ($flags{bracket} > 1 ? six_get('open-bracket') : undef), + ($flags{bracket} > 1 ? six_get('close-bracket') : undef), + $mantissa, + I_dual({}, # Means base^arg2, but looks like marker arg2 !! + I_apply({}, I_symbol({ meaning => 'power' }), six_get('exponent-base'), I_arg(1)), + I_wrap({}, $marker, I_arg(1)), + six_format_number($arg2, %flags, in_sci_number => 1, in_exponent => 1, bracket => 0))); } + else { + $result = I_dual({}, # Means base^arg2, but looks like marker arg2 !! I_apply({}, I_symbol({ meaning => 'power' }), six_get('exponent-base'), I_arg(1)), I_wrap({}, $marker, I_arg(1)), - six_format_number($arg2))); } + six_format_number($arg2, %flags, in_sci_number => 1, in_exponent => 1, bracket => 0)); } } else { - $result = six_format_infix( - ($$arg1{integer} || $$arg1{fraction} || $$arg1{operator} - ? six_get_op({ role => 'MULOP', meaning => 'times' }, 'exponent-product') - : T_CS('\lx@InvisibleTimes')), - ($bracket > 1 ? six_get('open-bracket') : undef), - ($bracket > 1 ? six_get('close-bracket') : undef), - six_format_number($arg1, 1), - I_superscript({ operator_meaning => 'power' }, six_get('exponent-base'), - six_format_number($arg2))); } +# the order of the conditionals is important here - $$arg1{integer} causes an $arg1 undef to become {} which is true + if ((six_getBool('print-unity-mantissa') && $arg1) + || ($$arg1{integer} && ToString($$arg1{integer}) ne '1') + || $$arg1{fraction} || $$arg1{operator}) { + my $mantissa = six_format_number($arg1, %flags, in_sci_number => 1, bracket => 0); + if ($flags{in_table_number} && six_getBool('table-align-exponent')) { + push(@{$mantissa}, six_table_space(${ $flags{pad_right_ref} })); + ${ $flags{pad_right_ref} } = ''; } + $result = six_format_infix( + ($$arg1{integer} || $$arg1{fraction} || $$arg1{operator} + ? six_get_op({ role => 'MULOP', meaning => 'times' }, 'exponent-product') + : T_CS('\lx@InvisibleTimes')), + ($flags{bracket} > 1 ? six_get('open-bracket') : undef), + ($flags{bracket} > 1 ? six_get('close-bracket') : undef), + $mantissa, + I_superscript({ operator_meaning => 'power' }, six_get('exponent-base'), + six_format_number($arg2, %flags, in_sci_number => 1, in_exponent => 1, bracket => 0))); } + else { + # there is no arg1 + if ($flags{in_table_number}) { + ${ $flags{pad_left_ref} } .= '2' x six_get('table-figures-uncertainty')->ToString; + ${ $flags{pad_left_ref} } .= '2' if (six_get('table-figures-uncertainty')->ToString); # for the () or +- + ${ $flags{pad_left_ref} } .= (six_getBool('table-sign-mantissa') ? '2' : '') + . ('2' x six_get('table-figures-integer')->ToString) + . '.' + . ('2' x six_get('table-figures-decimal')->ToString) . '2'; } # last 2 is for \times + $result = I_superscript({ operator_meaning => 'power' }, six_get('exponent-base'), + six_format_number($arg2, %flags, in_sci_number => 1, in_exponent => 1, bracket => 0)); } } # If mantissa is simple number, use scientific notation for the meaning # (all the dual cruft above formats appropriately, but is wasted) if ($arg1 && !$$arg1{operator} && (ToString(six_get('exponent-base')) eq '10')) { - $result = I_wrap({ meaning => six_number_string($number) }, $result); } + $$number{arg1} = $arg1; + $$number{arg2} = $arg2; + $result = I_wrap({ meaning => six_number_string($number) }, $result); } return $result; } sub six_format_compoundnumber { - my ($number, $bracket) = @_; + my ($number, %flags) = @_; my $op = $$number{operator}; my $arg1 = $$number{arg1}; my $arg2 = $$number{arg2}; + $flags{table_comparator_checked} = 1; my $result; - if ($op eq 'comparator') { + if ($flags{in_table_number} && (!$op || $op ne 'comparator')) { + # there should be a comparator, but isn't + ${ $flags{pad_left_ref} } = '2' . ${ $flags{pad_left_ref} }; + $result = I_wrap({}, six_format_number($number, %flags)); } + elsif ($op eq 'comparator') { # NOTE: Semantic? - $result = I_wrap({}, - ($$number{comparator} || ()), - six_format_number($arg1)); } + my $formatted = six_format_number($arg1, %flags); + if ($flags{in_table_number} && six_getBool('table-align-comparator')) { + unshift(@{$formatted}, six_table_space(${ $flags{pad_left_ref} })); + ${ $flags{pad_left_ref} } = ''; } + $result = I_wrap({}, ($$number{comparator} || ()), $formatted); } elsif ($op eq 'product') { - $result = six_format_infix( - six_get_op({ role => 'MULOP', meaning => 'times' }, 'output-product'), undef, undef, - six_format_number($arg1, 1), - six_format_number($arg2, 1)); } + my $times = six_get('product-mode')->toString eq 'symbol' + ? six_get_op({ role => 'MULOP', meaning => 'times' }, 'product-symbol') + : six_get_op({ role => 'MULOP', meaning => 'times', mode => 'TEXT' }, 'product-phrase'); + # but bracket? + my $bracket = $$arg1{operator} && $$arg1{operator} eq 'uncertain' && six_getBool('separate-uncertainty'); + $result = six_format_infix($times, undef, undef, + six_format_number($arg1, bracket => $bracket), six_format_number($arg2, bracket => $bracket)); } +# ($flags{bracket} ? six_get('open-bracket') : ()), ($flags{bracket} ? six_get('close-bracket') : ()), elsif ($op eq 'quotient') { if (six_getChoice('quotient-mode') eq 'fraction') { $result = Tokens( @@ -636,28 +1424,85 @@ sub six_format_compoundnumber { else { $result = six_format_infix( six_get_op({ role => 'MULOP', meaning => 'divide' }, 'output-quotient'), undef, undef, - six_format_number($arg1, 1), - six_format_number($arg2, 2)); } } + six_format_number($arg1, bracket => 1), + six_format_number($arg2, bracket => 2)); } } else { Error('unexpected', $op, undef, "Unrecognized operator $op in siunitx number"); } return $result; } +# Formats a number, by formatting each of the parts of the number +# By adjusting the %flags, this also allows us to format a tabular number (adding extra spacing) sub six_format_number { - my ($number, $bracket) = @_; + my ($number, %flags) = @_; return unless $number; return I_wrap({}, $number) unless ref $number eq 'HASH'; - $bracket = 0 unless $bracket && six_getBool('bracket-numbers'); - my @tokens = (); - if (my $op = $$number{operator}) { - my $arg1 = $$number{arg1}; - my $arg2 = $$number{arg2}; - if ($op eq 'uncertain') { push(@tokens, six_format_uncertainnumber($number, $bracket)); } - elsif ($op eq 'complex') { push(@tokens, six_format_complexnumber($number, $bracket)); } - elsif ($op eq 'exponent') { push(@tokens, six_format_scinumber($number, $bracket)); } - else { push(@tokens, six_format_compoundnumber($number, $bracket)); } } + $flags{bracket} = 0 unless $flags{bracket} && six_getBool('bracket-numbers') && six_getBool('bracket-ambiguous-numbers'); + my (@tokens, @trailer); + my $sign = $$number{sign}; + my $op = $$number{operator} || 0; + my $needs_sign_space = 0; + # these are ordered according to how we parse a number + # once the number or the table formatter indicate something, we'll take that route + if ($flags{in_table_number}) { + if (!$flags{table_comparator_checked} && ($op eq 'comparator' || six_getBool('table-comparator'))) { + $op = 'comparator'; } + elsif (!$flags{table_exponent_checked} && ($op eq 'exponent' || six_get('table-figures-exponent')->toString)) { + $op = 'exponent'; } + elsif (!$flags{table_uncertain_checked} && ($op eq 'uncertain' || six_get('table-figures-uncertainty')->toString)) { + $op = 'uncertain'; } } + if ($sign) { + delete $$number{sign}; + if (ToString($sign) eq '-') { + if ($op || !number_is_zero($$number{integer}) || !number_is_zero($$number{fraction}) || $$number{rounded_negative} + || six_getBool('retain-negative-zero') || ($flags{in_sci_number} && !$flags{in_exponent})) { + my $c = six_get('negative-color'); + if ($c && $op ne 'complex' && !$flags{in_complex_number}) { + push(@tokens, T_BEGIN, T_CS('\color'), T_BEGIN, $c->unlist, T_END); + unshift(@trailer, T_END); } + if (six_getBool('bracket-negative-numbers') && $op ne 'complex' && !$flags{in_complex_number}) { + push(@tokens, six_get('open-bracket')); + $sign = undef; + unshift(@trailer, six_get('close-bracket')); } } } + my $mant_exp = $flags{in_exponent} ? 'exponent' : 'mantissa'; + if ($sign && $sign->ToString eq '+') { + if (six_getBool('print-' . $mant_exp . '-implicit-plus', 'retain-explicit-plus') && !$flags{ $mant_exp . '_implicit_plus_present' }) { + $flags{ $mant_exp . '_implicit_plus_present' } = 1; } + else { + $sign = undef } } + push(@tokens, $sign) if ($sign); } + elsif ($flags{in_exponent}) { + if (six_getBool('print-exponent-implicit-plus') && !$flags{exponent_implicit_plus_present}) { + $flags{exponent_implicit_plus_present} = 1; + push(@tokens, T_OTHER('+')); } + elsif ($flags{in_table_number} && six_getBool('table-sign-exponent')) { + ${ $flags{pad_right_ref} } .= '.'; } } + elsif (!$flags{in_sci_number}) { + if (six_getBool('print-mantissa-implicit-plus') && !$flags{mantissa_implicit_plus_present}) { + $flags{mantissa_implicit_plus_present} = 1; + push(@tokens, T_OTHER('+')); } + elsif ($flags{in_table_number} && six_getBool('table-sign-mantissa')) { + ${ $flags{pad_left_ref} } .= '2'; } } + if ($op) { + if ($op eq 'uncertain') { push(@tokens, six_format_uncertainnumber($number, %flags)); } + elsif ($op eq 'complex') { push(@tokens, six_format_complexnumber($number, %flags, in_complex_number => 1)); } + elsif ($op eq 'exponent') { push(@tokens, six_format_scinumber($number, %flags)); } + else { push(@tokens, six_format_compoundnumber($number, %flags)); } } else { - push(@tokens, six_format_simplenumber($number, $bracket)); } - return Tokens(@tokens); } + push(@tokens, six_format_simplenumber($number, %flags)); } + return Tokens(@tokens, @trailer); } + +# we create space with a makebox of the appropriate width (hphantom, ~, and \, didn't work) +# we would like to use the actual content (similar to hphantom), but it's hard to determine that width (see also #2768) +# instead, we'll track the content as some count of 2 and ., translating the latter to half the width of the former +# for debugging, you can change makebox to framebox (but again #2768) or print the spacer in the {} +my $DIGIT_WIDTH = 200000; # Box('2')->getWidth->[0] is 327681; this is an approximation + +sub six_table_space { + my ($spacer) = @_; + #return Tokenize('\framebox[' . Box($spacer)->getWidth->[0] . 'sp]{'. $spacer .'}'); + my @twos = $spacer =~ /2/g; + my @dots = $spacer =~ /\./g; + return Tokenize('\makebox[' . $DIGIT_WIDTH * (2 * @twos + @dots) . 'sp]{}'); } # ' . $spacer .' # Return the plain-text string for a number, for use in meaning attribute # Note that the format is pretty ad-hoc, except for simple-numbers @@ -694,6 +1539,7 @@ sub six_number_string { 'E', six_number_string($arg2), ($bracket > 1 ? ')' : '')); } else { + Error('formatting', 'unknown format', undef, "Unkown number format"); return "Unkown number format"; } } else { my $sign = $$number{sign}; @@ -701,8 +1547,7 @@ sub six_number_string { my $fraction = $$number{fraction}; # Wrong!!! return join('', ToString($sign), ToString($integer), - ($fraction ? '.' . ToString($fraction) : '')); -} } + ($fraction ? '.' . ToString($fraction) : '')); } } #====================================================================== @@ -712,8 +1557,11 @@ sub six_format_range { six_get_op({ role => 'PUNCT' }, 'range-phrase'), I_arg(2)); if ($bracketed_p) { - unshift(@range, six_get_op({ role => 'OPEN' }, 'open-bracket')); - push(@range, six_get_op({ role => 'CLOSE' }, 'close-bracket')); } + unshift(@range, six_get_op({ role => 'OPEN' }, 'range-open-bracket', 'open-bracket')); + push(@range, six_get_op({ role => 'CLOSE' }, 'range-close-bracket', 'close-bracket')); } + if (six_get('range-open-phrase')) { + # todo: Warning:not_parsed:>PUNCT MathParser failed to match rule 'Anything' + unshift(@range, six_get_op({ role => 'PUNCT' }, 'range-open-phrase')); } return I_dual({}, I_apply({}, I_symbol({ meaning => 'range' }), I_arg(1), I_arg(2)), I_wrap({}, @range), @@ -737,8 +1585,8 @@ sub six_format_list { push(@list, six_get_op({ role => 'PUNCT' }, 'list-final-separator'), I_arg($nitems)); } if (($nitems > 1) && $bracketed_p) { - unshift(@list, six_get_op({ role => 'OPEN' }, 'open-bracket')); - push(@list, six_get_op({ role => 'CLOSE' }, 'close-bracket')); } + unshift(@list, six_get_op({ role => 'OPEN' }, 'list-open-bracket', 'open-bracket')); + push(@list, six_get_op({ role => 'CLOSE' }, 'list-close-bracket', 'close-bracket')); } return I_dual({}, I_apply({}, I_symbol({ meaning => 'list' }), map { I_arg($_); } 1 .. $nitems), I_wrap({}, @list), @@ -762,29 +1610,133 @@ sub six_wrap { DefMacro('\num OptionalKeyVals:SIX {}', sub { my ($gullet, $kv, $number) = @_; six_begin_processing($gullet, $kv); - my $result = six_wrap(six_format_number(six_parse_number($gullet, $number))); + my $parsed = six_parse_number($gullet, $number); + my $product_exponents = six_getChoice('product-exponents'); + my $min_exp = undef; + if ($product_exponents =~ /combine/) { + # you are a bad person + my $other = $parsed; + while ($$other{operator} && $$other{operator} eq 'product') { + my $next_exp = six_get_sci_exp($$other{arg2}); + if (!defined $min_exp || $next_exp < $min_exp) { + $min_exp = $next_exp; } + $other = $$other{arg1}; } + my $next_exp = six_get_sci_exp($other); + if (!defined $min_exp || $next_exp < $min_exp) { + $min_exp = $next_exp; } + $other = $parsed; + my $container; + while ($$other{operator} && $$other{operator} eq 'product') { + $$other{arg2} = six_get_number_with_sci_exp($$other{arg2}, $min_exp); + $container = $other; + $other = $$other{arg1}; } + $$container{arg1} = six_get_number_with_sci_exp($other, $min_exp); } + my $formatted = six_format_number($parsed); + if ($product_exponents =~ /combine/ && ($min_exp || six_getBool('print-zero-exponent'))) { + if ($product_exponents eq 'combine-bracket') { + $formatted = six_wrap(six_get('open-bracket'), $formatted, six_get('close-bracket')); } + $formatted = six_format_infix(six_get_op({ role => 'MULOP', meaning => 'times' }, 'exponent-product'), + undef, undef, $formatted, + I_superscript({ operator_meaning => 'power' }, six_get('exponent-base'), + six_format_number({ integer => Tokenize($min_exp) }, bracket => 0, in_sci_number => 1))); } + my $result = six_wrap($formatted); six_end_processing(); return $result; }); +Let('\tablenum', '\num'); # was \lx@table@num +Let(T_CS('\complexnum'), T_CS('\num')); +Let(T_CS('\numproduct'), T_CS('\num')); # \numlist[options]{number;number;...} DefMacro('\numlist OptionalKeyVals:SIX {}', sub { my ($gullet, $kv, $numbers) = @_; six_begin_processing($gullet, $kv); - my @numbers = six_parse_numbers($gullet, $numbers); - my @formatted = six_wrap(six_format_list(0, map { six_format_number($_); } @numbers)); + my @numbers = six_parse_numbers($gullet, $numbers); + if (six_get('list-input-separator')->toString eq six_get('complex-angle-separator')->toString) { + my @new_numbers = (); + foreach my $number (@numbers) { + if ($$number{arg1} and $$number{arg2} and $$number{operator} eq 'complex' and $$number{input_form} eq 'polar') { + push(@new_numbers, $$number{arg1}, $$number{arg2}); } + else { + push(@new_numbers, $number); } } + @numbers = @new_numbers; } + my $list_exponents = six_getChoice('list-exponents'); + my $min_exp; + if ($list_exponents =~ /combine/) { + $min_exp = six_get_sci_exp($numbers[0]); + for my $number (@numbers) { + my $this_exp = six_get_sci_exp($number); + if ($this_exp < $min_exp) { + $min_exp = $this_exp; } } + for my $i (0 .. $#numbers) { + $numbers[$i] = six_get_number_with_sci_exp($numbers[$i], $min_exp); } } + my $formatted = six_format_list($list_exponents eq 'combine-bracket', map { six_format_number($_); } @numbers); + if ($list_exponents =~ /combine/ && ($min_exp || six_getBool('print-zero-exponent'))) { + $formatted = six_format_infix(six_get_op({ role => 'MULOP', meaning => 'times' }, 'exponent-product'), + undef, undef, $formatted, + I_superscript({ operator_meaning => 'power' }, six_get('exponent-base'), + six_format_number({ integer => Tokenize(abs($min_exp)), sign => Token($min_exp < 0 ? '-' : '') }, bracket => 0, in_sci_number => 1))); } + my @wrapped = six_wrap($formatted); six_end_processing(); - return Tokens(@formatted); }); + return Tokens(@wrapped); }); # \numrange[options]{first}{last} DefMacro('\numrange OptionalKeyVals:SIX {}{}', sub { my ($gullet, $kv, $first, $last) = @_; six_begin_processing($gullet, $kv); - my $result = six_wrap(six_format_range(0, - six_format_number(six_parse_number($gullet, $first)), - six_format_number(six_parse_number($gullet, $last)))); + my $first_parsed = six_parse_number($gullet, $first); + my $last_parsed = six_parse_number($gullet, $last); + my $range_exponents = six_getChoice('range-exponents'); + my ($first_exp, $last_exp); + if ($range_exponents =~ /combine/) { + $first_exp = six_get_sci_exp($first_parsed); + $last_exp = six_get_sci_exp($last_parsed); + if ($last_exp < $first_exp) { + $first_parsed = six_get_number_with_sci_exp($first_parsed, $last_exp); + $last_parsed = $$last_parsed{arg1}; } + elsif ($first_exp < $last_exp) { + $first_parsed = $$first_parsed{arg1}; + $last_parsed = six_get_number_with_sci_exp($last_parsed, $first_exp); + # now make $last_exp the smaller + $last_exp = $first_exp; } + else { + $first_parsed = $$first_parsed{arg1}; + $last_parsed = $$last_parsed{arg1}; } } + my $formatted = six_format_range($range_exponents eq 'combine-bracket', + six_format_number($first_parsed), + six_format_number($last_parsed)); + if ($range_exponents =~ /combine/ && ($first_exp || six_getBool('print-zero-exponent'))) { + $formatted = six_format_infix(six_get_op({ role => 'MULOP', meaning => 'times' }, 'exponent-product'), + undef, undef, $formatted, + I_superscript({ operator_meaning => 'power' }, six_get('exponent-base'), + six_format_number({ integer => Tokenize(abs($last_exp)), sign => Token($last_exp < 0 ? '-' : '') }, bracket => 0, in_sci_number => 1))); } + my $result = six_wrap($formatted); six_end_processing(); return $result; }); +# transform {number} or {arg1=>number, operator=>'exponent', arg2=>number} +# into a number with a specified exponent +# only returns the arg1, not the operator nor the arg2 exponent +sub six_get_number_with_sci_exp { + my ($number, $new_exp) = @_; + my $old_exp = six_get_sci_exp($number); + $number = $$number{arg1} if $$number{operator} && $$number{operator} eq 'exponent'; + if ($old_exp != $new_exp) { + my @intTokens = $$number{integer} ? $$number{integer}->unlist : (); + my @fracTokens = $$number{fraction} ? $$number{fraction}->unlist : (); + while ($old_exp < $new_exp) { + $old_exp++; + unshift(@fracTokens, (pop(@intTokens) || T_OTHER('0'))); } + while ($new_exp < $old_exp) { + $old_exp--; + push(@intTokens, (shift(@fracTokens) || T_OTHER('0'))); } + $$number{integer} = @intTokens ? Tokens(@intTokens) : undef; + if (@fracTokens) { + $$number{fraction} = Tokens(@fracTokens); } + else { + delete $$number{decimal}; + delete $$number{fraction}; } } + return $number; } + # These are in serious need of tweaking! DefMacro('\lx@arcdegreeoverdot', '\lx@stackrel{\SIUnitSymbolDegree}{.}'); DefMacro('\lx@arcminuteoverdot', '\lx@stackrel{{\scriptstyle\prime}}{.}'); @@ -801,74 +1753,102 @@ DefMacro('\ang OptionalKeyVals:SIX {}', sub { six_begin_processing($gullet, $kv); # We REALLY should only allow simplenumbers (even without uncertainty!)! my ($degrees, $minutes, $seconds) = six_parse_numbers($gullet, $expr); - # Normalize integer/fraction part. - my $addd0 = !$degrees && six_getBool('add-arc-degree-zero'); - my $addm0 = !$minutes && six_getBool('add-arc-minute-zero') - && (!$degrees || !$$degrees{fraction}); - my $adds0 = !$seconds && six_getBool('add-arc-second-zero') - && (!$degrees || !$$degrees{fraction}) - && (!$minutes || !$$minutes{fraction}); - $degrees = { integer => T_OTHER('0') } if $addd0; - $minutes = { integer => T_OTHER('0') } if $addm0; - $seconds = { integer => T_OTHER('0') } if $adds0; - + if (six_getChoice('angle-mode') eq 'arc' && $$degrees{fraction}) { + my $oldFraction = UnTeX($$degrees{fraction}); + my $angle = $oldFraction * 60 / (10**scalar(@{ $$degrees{fraction} })); + $minutes = six_parse_number(undef, Tokenize($angle)); + delete $$degrees{decimal}; + delete $$degrees{fraction}; + if ($$minutes{fraction}) { + $oldFraction = UnTeX($$minutes{fraction}); + $angle = $oldFraction * 60 / (10**scalar(@{ $$minutes{fraction} })); + $seconds = six_parse_number(undef, Tokenize($angle)); + delete $$minutes{decimal}; + delete $$minutes{fraction}; } } + if (six_getChoice('angle-mode') eq 'decimal' && ($minutes || $seconds)) { + my $fraction = six_parse_number(undef, Tokenize((UnTeX($$minutes{integer}) + UnTeX($$seconds{integer}) / 60) / 60)); + $$degrees{decimal} = $$fraction{decimal}; + $$degrees{fraction} = $$fraction{fraction}; + $minutes = undef; + $seconds = undef; } # Pull out the (overall) sign, assuming(!) the first one applies to all components. my $sign = ($degrees && $$degrees{sign}) || ($minutes && $$minutes{sign}) || ($seconds && $$seconds{sign}); - $$degrees{sign} = undef if $degrees; - $$minutes{sign} = undef if $minutes; - $$seconds{sign} = undef if $seconds; - my @punctuated = (); - my $sep1 = six_get('number-angle-product'); - my $sep2 = six_get('arc-separator'); - my $mulop = I_wrap({ role => 'MULOP', meaning => 'times' }, - ($sep1->unlist ? $sep1 : T_CS('\lx@InvisibleTimes'))); - my $addop = I_wrap({ role => 'ADDOP', meaning => 'plus' }, - ($sep2->unlist ? $sep2 : T_CS('\lx@InvisiblePlus'))); - my $above = six_get('angle-symbol-over-decimal'); - my $save = six_get('copy-decimal-marker'); - AssignValue('SIX_copy-decimal-marker' => 'true'); - # Format degrees, if any - if ($above && $degrees && $$degrees{decimal}) { - $$degrees{decimal} = T_CS('\lx@arcdegreeoverdot'); } - my $fdegrees = $degrees && six_format_number($degrees); - if ($fdegrees && $fdegrees->unlist) { - push(@punctuated,($above && $$degrees{decimal} ? $fdegrees - : I_apply({},$mulop,$fdegrees, T_CS('\SIUnitSymbolDegree')))); } - # Format minues, if any - if ($above && $minutes && $$minutes{decimal}) { - $$minutes{decimal} = T_CS('\lx@arcminuteoverdot'); } - my $fminutes = $minutes && six_format_number($minutes); - if ($minutes && $fminutes->unlist) { - push(@punctuated,($above && $$minutes{decimal} ? $fminutes - : I_apply({},$mulop,$fminutes, T_CS('\SIUnitSymbolArcminute')))); } - - # Format seconds, if any - if ($above && $seconds && $$seconds{decimal}) { - $$seconds{decimal} = T_CS('\lx@arcsecondoverdot'); } - my $fseconds = $seconds && six_format_number($seconds); - if ($seconds && $fseconds->unlist) { - push(@punctuated,($above && $$seconds{decimal} ? $fseconds - : I_apply({},$mulop,$fseconds,T_CS('\SIUnitSymbolArcsecond')))); } - if(scalar(@punctuated) > 1){ - @punctuated = (I_apply({},$addop,@punctuated)); } - if ($sign) { # Finally, prepend the sign - @punctuated = I_apply({},$sign,@punctuated); } - AssignValue('SIX_copy-decimal-marker' => $save); - my $string = join('', - ToString($sign), - ($degrees ? six_number_string($degrees) . "\x{00B0}" : ''), - ($minutes ? six_number_string($minutes) . "\x{2032}" : ''), - ($seconds ? six_number_string($seconds) . "\x{2033}" : '')); - my $result = six_wrap(I_dual({}, I_symbol({ role => 'NUMBER', meaning => $string }), - I_wrap({}, @punctuated))); - six_end_processing(); - return $result; }); + delete $$degrees{sign} if $degrees; + delete $$minutes{sign} if $minutes; + delete $$seconds{sign} if $seconds; + if (!($degrees && %$degrees) || is_explicit_zero($degrees)) { + if (six_getBool('fill-angle-degrees')) { + $degrees = { integer => T_OTHER('0') }; } + else { + $degrees = undef; } } + if (!($minutes && %$minutes && !is_explicit_zero($minutes)) + && (!$degrees || !%$degrees || !$$degrees{fraction})) { + if (six_getBool('fill-angle-minutes')) { + $minutes = { integer => T_OTHER('0') }; } + else { + $minutes = undef; } } + if (!($seconds && %$seconds && !is_explicit_zero($seconds)) + && (!$degrees || !%$degrees || !$$degrees{fraction}) + && (!$minutes || !%$minutes || !$$minutes{fraction})) { + if (six_getBool('fill-angle-seconds')) { + $seconds = { integer => T_OTHER('0') }; } + else { + $seconds = undef; } } + return six_format_angle($sign, $degrees, $minutes, $seconds); }); + +sub six_format_angle { + my ($sign, $degrees, $minutes, $seconds) = @_; + my @punctuated = (); + six_enableUnitMacros(1); + my $sep1 = six_get('number-angle-product'); + my $sep2 = six_get('angle-separator', 'arc-separator'); + my $mulop = I_wrap({ role => 'MULOP', meaning => 'times' }, ($sep1->unlist ? $sep1 : T_CS('\lx@InvisibleTimes'))); + my $addop = I_wrap({ role => 'ADDOP', meaning => 'plus' }, ($sep2->unlist ? $sep2 : T_CS('\lx@InvisiblePlus'))); + my $above = six_getBool('angle-symbol-over-decimal'); + my $save = six_get('copy-decimal-marker'); + AssignValue('SIX_copy-decimal-marker' => 'true') if ($above); + # Format degrees, if any + if ($above && $degrees && $$degrees{decimal}) { + $$degrees{decimal} = T_CS('\lx@arcdegreeoverdot'); } + my $fdegrees = $degrees && six_format_number($degrees); + if ($fdegrees && $fdegrees->unlist) { + push(@punctuated, ($above && $$degrees{decimal} ? $fdegrees + : I_apply({}, $mulop, $fdegrees, Expand(six_get('angle-symbol-degree'))))); } + # Format minutes, if any + if ($above && $minutes && $$minutes{decimal}) { + $$minutes{decimal} = T_CS('\lx@arcminuteoverdot'); } + my $fminutes = $minutes && six_format_number($minutes); + if ($minutes && $fminutes->unlist) { + push(@punctuated, ($above && $$minutes{decimal} ? $fminutes + : I_apply({}, $mulop, $fminutes, Expand(six_get('angle-symbol-minute'))))); } + # Format seconds, if any + if ($above && $seconds && $$seconds{decimal}) { + $$seconds{decimal} = T_CS('\lx@arcsecondoverdot'); } + my $fseconds = $seconds && six_format_number($seconds); + if ($seconds && $fseconds->unlist) { + push(@punctuated, ($above && $$seconds{decimal} ? $fseconds + : I_apply({}, $mulop, $fseconds, Expand(six_get('angle-symbol-second'))))); } + if (scalar(@punctuated) > 1) { + @punctuated = (I_apply({}, $addop, @punctuated)); } + if ($sign && ($sign->toString ne '+' || six_getBool('retain-explicit-plus'))) { # Finally, prepend the sign + @punctuated = I_apply({}, $sign, @punctuated); } + AssignValue('SIX_copy-decimal-marker' => $save) if ($above); + my $string = join('', + ToString($sign), + ($degrees ? six_number_string($degrees) . "\x{00B0}" : ''), + ($minutes ? six_number_string($minutes) . "\x{2032}" : ''), + ($seconds ? six_number_string($seconds) . "\x{2033}" : '')); + my $result = six_wrap(I_dual({}, I_symbol({ role => 'NUMBER', meaning => $string }), + I_wrap({}, @punctuated))); + six_end_processing(); + return $result; } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Processing Units # Unit processing macros +# Converts {first}rest into (Tokens(first),rest), paying attention to grouping sub six_peel_group { my (@tokens) = @_; if (@tokens && $tokens[0]->getCatcode == CC_BEGIN) { @@ -888,6 +1868,27 @@ sub six_peel_group { else { return (undef, @tokens); } } +# Converts rest{last} into (Tokens(last), rest), paying attention to grouping +# note that the order switches, because Tokens returns a scalar +sub six_peel_tail_group { + my (@tokens) = @_; + if (@tokens && $tokens[-1]->getCatcode == CC_END) { + pop(@tokens); + my @result = (); + my $level = 1; + while (@tokens) { + my $t = pop(@tokens); + my $cc = $t->getCatcode; + if ($cc == CC_BEGIN) { + $level--; + last unless $level; } + elsif ($cc == CC_END) { + $level++; } + unshift(@result, $t); } + return (Tokens(@result), @tokens); } + else { + return (undef, @tokens); } } + # Turn all the internal definitions into real macros AssignValue(siunitx_macros => {}); @@ -916,6 +1917,9 @@ sub six_convertUnits { ($arg, @tokens) = six_peel_group(@tokens); my $newdefn = { %{ LookupMapping('siunitx_macros', ToString($name)) } }; if (my $argkey = $$newdefn{arg}) { + #my $qmode = six_getChoice('qualifier-mode') if ($argkey eq 'qualifier'); + #$qmode = 'combine' if $qmode eq 'text'; + #$$newdefn{qmode} = $qmode; $$newdefn{$argkey} = $arg; } push(@defns, $newdefn); } elsif ($tokens[0]->equals(T_SPACE)) { @@ -951,7 +1955,7 @@ sub six_parse_units { push(@save, shift(@defns)); } } # Else save for next unit! } if ((!keys %$unit) && @defns) { - Error('unexpected', $defns[0]{name}, undef, "Don't know what to do with si unit."); + Error('unexpected', $defns[0]{name}, undef, "Don't know what to do with si unit"); return (); } # Error if no unit, unless pure prefix(?) elsif (!$$unit{unit} && !($$unit{prefix} && !$$unit{qualifier} && !$$unit{power})) { @@ -969,37 +1973,70 @@ sub six_parse_units { # Format a single unit sub six_format_1unit { my ($unit) = @_; - my $per = $$unit{per}; - my $pre = $$unit{prefix}{presentation}; + my $prefix = $$unit{prefix}{presentation}; my $u = $$unit{unit}{presentation}; - my $p = $$unit{prepower}{power} || $$unit{postpower}{power}; + my $power = $$unit{prepower}{power} || $$unit{postpower}{power}; my $q = $$unit{qualifier}{presentation}; - if ($per) { # NOTE: Probably deal with this more semantically (ie "per" for accessibility)? - $p = ($p ? Tokens(T_OTHER('-'), $p) : Tokens(T_OTHER('-'), T_OTHER('1'))); } - if ($q) { # Format the qualifier, if any - my $qmode = six_getChoice('qualifier-mode'); - if ($qmode eq 'subscript') { - $q = Tokens(T_SUB(), T_BEGIN, T_CS('\mathrm'), T_BEGIN, $q, T_END, T_END); } - elsif ($qmode eq 'brackets') { - $q = Tokens(six_get('open-bracket'), T_CS('\mathrm'), T_BEGIN, $q, T_END, six_get('close-bracket')); } - elsif (($qmode eq 'phrase') || ($qmode eq 'space')) { - my $sep = ($qmode eq 'phrase' ? six_get('qualifier-phrase') : T_CS('\;')); - $u = Tokens(($p ? six_get('open-bracket') : ()), - ($pre ? $pre : ()), - $u, $sep, $q, - ($p ? six_get('close-bracket') : ())); - $q = $pre = undef; } - elsif ($qmode eq 'text') { - $q = Tokens(T_CS('\mathrm'), T_BEGIN, $q, T_END) } } - # Apparently best to treat $pre & $u as a single symbol? AND probably the qualifier? + my $meaning = ($prefix ? $$unit{prefix}{name} : '') . ($u ? $$unit{unit}{name} : '') . ($q ? '-' . $$unit{qualifier}{name} : ''); + if ($$unit{per}) { # NOTE: Probably deal with this more semantically (ie "per" for accessibility)? + $power = Tokens(T_OTHER('-'), $power || T_OTHER('1')); } + # my $bracket_qualifier = $power; + if ($q) { # Format the qualifier, if any + my $qmode = six_get('qualifier-mode')->toString; + $qmode =~ s/s$//; + $qmode = 'combine' if $qmode eq 'text'; + #$bracket_qualifier &&= ($qmode eq 'phrase') || ($qmode eq 'space') || ($qmode eq 'combine'); + $q = Invocation(T_CS('\lx@six@of@' . $qmode), + $$unit{qualifier}{arg} ? $$unit{qualifier}{ $$unit{qualifier}{arg} } : $q, + $qmode eq 'phrase' ? six_get('qualifier-phrase') : ()); + if ($power && (($qmode eq 'phrase') || ($qmode eq 'space') || ($qmode eq 'combine'))) { + $u = Tokens(six_get('open-bracket'), ($prefix || ()), $u, $q, six_get('close-bracket')); + $meaning ||= ($prefix ? $$unit{prefix}{name} : '') . ($u ? $$unit{unit}{name} : '') + . ($q ? '-' . $$unit{qualifier}{name} : ''); + $q = $prefix = undef; } } +# if ($$unit{qualifier}{arg}) { +# $bracket_qualifier &&= ($$unit{qualifier}{qmode} eq 'phrase') || ($$unit{qualifier}{qmode} eq 'space') || ($$unit{qualifier}{qmode} eq 'combine'); +# $q = Invocation(T_CS($$unit{qualifier}{implementation}->ToString . '@' . $$unit{qualifier}{qmode}), $$unit{qualifier}{ $$unit{qualifier}{arg} }); } +# else { +# # we have to determine qmode before ending the group +# $bracket_qualifier &&= ($qmode eq 'phrase') || ($qmode eq 'space') || ($qmode eq 'combine'); +# $q = Invocation(T_CS('\lx@six@of@'.$qmode), $q); } } +# if ( $bracket_qualifier ) { +# $u = Tokens(six_get('open-bracket'), ($prefix||()), $u, $q, six_get('close-bracket')); +# $meaning ||= ($prefix ? $$unit{prefix}{name} : '') . ($u ? $$unit{unit}{name} : '') +# . ($q ? '-' . $$unit{qualifier}{name} : ''); +# $q = $prefix = undef; } +# my $qmode = six_getChoice('qualifier-mode'); +# if ($qmode eq 'subscript') { +# $q = Tokens(T_SUB, T_BEGIN, T_CS('\mathrm'), T_BEGIN, $q, T_END, T_END); } +# elsif ($qmode =~ /^brackets?$/) { +# $q = Tokens(six_get('open-bracket'), T_CS('\mathrm'), T_BEGIN, $q, T_END, six_get('close-bracket')); } +# elsif (($qmode eq 'phrase') || ($qmode eq 'space') || ($qmode eq 'text')) { +# my $sep = $qmode eq 'phrase' ? six_get('qualifier-phrase') : ($qmode eq 'space' ? T_CS('\;') : Tokens()); +# $u = Tokens(($power ? six_get('open-bracket') : ()), +# ($prefix ? $prefix : ()), +# $u, $sep, $q, +# ($power ? six_get('close-bracket') : ())); +# $q = $prefix = undef; } +# elsif ($qmode eq 'text') { +# $q = Tokens(T_CS('\mathrm'), T_BEGIN, $q, T_END) } } +# $meaning ||= ($prefix ? $$unit{prefix}{name} : '') . ($u ? $$unit{unit}{name} : '') +# . ($q ? '-' . $$unit{qualifier}{name} : ''); +# Apparently best to treat $prefix & $u as a single symbol? AND probably the qualifier? my $result = Tokens( T_CS('\lx@unit'), - T_OTHER(($pre ? $$unit{prefix}{name} : '') . ($u ? $$unit{unit}{name} : '') - . ($q ? '-' . $$unit{qualifier}{name} : '')), - T_BEGIN, Invocation(T_CS('\mathrm'), Tokens(($pre ? $pre : ()), ($u ? $u : ()))), - ($q ? $q : ()), T_END); - if ($p) { - $result = Tokens(T_CS('\lx@power'), T_BEGIN, $result, T_END, T_BEGIN, $p, T_END); } + T_BEGIN, + T_OTHER($meaning), + T_END, + T_BEGIN, + Invocation(T_CS('\mathrm'), Tokens(($prefix ? $prefix : ()), ($u ? $u : ()))), + ($q ? $q : ()), + T_END); + if ($power) { + if ($power->toString !~ /-/ && $power->toString == 0.5 && six_getBool('power-half-as-sqrt')) { + $result = Tokens(T_CS('\sqrt'), T_BEGIN, $result, T_END); } + else { + $result = Tokens(T_CS('\lx@power'), T_BEGIN, $result, T_END, T_BEGIN, $power, T_END); } } if ($$unit{cancel}) { $result = Tokens(T_CS('\cancel'), T_BEGIN, $result, T_END); } if (my $color = $$unit{highlight}{color}) { @@ -1041,28 +2078,33 @@ sub six_format_unitproduct { # Format multiple (product of) units sub six_format_units { my (@units) = @_; - # Most complexity here is how to deal with "per", negative powers, and grouping of units - my $p2 = 0; - my $p10 = 0; - # This option MODIFIES the units objects, extracts (removing) all prefixes - # all prefixes are combined into a single common power of 10 or 2, at the front - if (!six_getBool('prefixes-as-symbols')) { + # per-mode options: reciprocal (nee power), fraction, reciprocal-positive-first, + # symbol, symbol-or-fraction, single-symbol + my $mathstyle = LookupValue('font')->getMathstyle || 'text'; + my $mode = $mathstyle eq 'display' ? 'display' : 'inline'; + my $permode = six_getBool('parse-units') ? six_getChoice($mode . '-per-mode') : 'symbol'; + my $prefixMode = six_getChoice('prefix-mode'); + if ($permode eq 'symbol-or-fraction') { + $permode = $mathstyle eq 'display' ? 'fraction' : 'symbol'; } + my $result = Tokens(); + my $currPower = 0; + if (!six_getBool('prefixes-as-symbols')) { # $prefixMode eq 'extract-exponent' || + my $base; foreach my $unit (@units) { - if (my $pre = $$unit{prefix}) { - my $p = ToString($$unit{prepower}{power} || $$unit{postpower}{power} || 1) - * ($$unit{per} ? -1 : +1); - if ($$pre{base} == 2) { $p2 += $p * ToString($$pre{power}); } - else { $p10 += $p * ToString($$pre{power}); } - $$unit{prefix} = undef; - if (($$unit{unit}{name} || '') eq 'gram') { # Special case: keep kilograms! - $$unit{prefix} = LookupMapping('siunitx_macros', 'kilo'); - $p10 -= 3 * $p; } } } } - # per-mode = reciprocal, fraction, reciprocal-positive-first, symbol, symbol-or-fraction - my $permode = six_getChoice('per-mode'); - if ($permode eq 'symbol-or-fraction') { # in display use fraction, otherwise symbol - $permode = ((LookupValue('font')->getMathstyle || 'text') eq 'display' ? 'fraction' : 'symbol'); } - my $result = Tokens(); - if ($permode eq 'reciprocal') { # Each unit processed, in order, with its own per (if any) + my $unitMult = ToString($$unit{prepower}{power} || $$unit{postpower}{power} || 1) * ($$unit{per} ? -1 : +1); + if (my $prefix = $$unit{prefix}) { + $currPower += $unitMult * ToString($$prefix{power}); + if ($base) { + if ($$unit{prefix}{base} != $base) { + Error('unexpected', undef, undef, "Prefix bases do not match: Expected $base, found $$unit{prefix}{base}"); } } + else { + $base = $$unit{prefix}{base}; } + delete $$unit{prefix}; } + if (($$unit{unit}{name} || '') eq 'gram' && six_getBool('extract-mass-in-kilograms')) { # Special case: keep kilograms! + $currPower -= 3 * $unitMult; + $$unit{prefix} = LookupMapping('siunitx_macros', 'kilo'); } } + AssignValue('SIX_exponent-base' => Tokenize($base)) if $currPower; } + if ($permode eq 'reciprocal' || $permode eq 'power') { # Each unit processed, in order, with its own per (if any) $result = six_format_unitproduct(0, @units); } else { # Otherwise, we've got to collect num & denom, possibly into a fraction my @numer = (); @@ -1070,15 +2112,19 @@ sub six_format_units { foreach my $unit (@units) { # Separate into positive & negative powers. if ($$unit{per}) { push(@denom, $unit); } else { push(@numer, $unit); } } - if ($permode eq 'reciprocal-positive-first') { # re-ordered, otherwise each per as-is. + if ($permode eq 'single-symbol' && (scalar(@denom) != 1 || scalar(@numer) == 0)) { + $result = six_format_unitproduct(0, @units); } # single-symbol fails. repeat $permode eq 'power' + elsif ($permode eq 'reciprocal-positive-first' || $permode eq 'power-positive-first') { + # re-ordered, otherwise each per as-is. $result = six_format_unitproduct(0, @numer, @denom); } - else { # Otherwise, remove per markers from denom. - map { $$_{per} = undef; } @denom; # MODIFY the denominator units! + else { # Otherwise, remove per markers from denom. + map { delete $$_{per}; } @denom; # MODIFY the denominator units! if ($permode eq 'fraction') { - $result = Tokens(T_CS('\frac'), + $result = Tokens(six_get('fraction-command'), T_BEGIN, six_format_unitproduct(0, @numer), T_END, T_BEGIN, six_format_unitproduct(0, @denom), T_END); } - elsif ($permode eq 'repeated-symbol') { + elsif ($permode eq 'repeated-symbol' || $permode eq 'single-symbol') { + # if single-symbol, then @denom==1 and @numer>0 from above my $per = six_get_op({ role => 'MULOP', meaning => 'divide' }, 'per-symbol'); $result = six_format_unitproduct(0, @numer); foreach my $denom (@denom) { # special symbol prefixes each denom unit @@ -1088,17 +2134,14 @@ sub six_format_units { $result = six_format_infix( six_get_op({ role => 'MULOP', meaning => 'divide' }, 'per-symbol'), undef, undef, - six_format_unitproduct(0, @numer), - six_format_unitproduct($bracket, @denom)); } + six_format_unitproduct(0, @numer), + (@denom ? six_format_unitproduct($bracket, @denom) : ())); } else { Error('unexpected', $permode, undef, "Unknown siunitx per-mode $permode"); } } } - if ($p2 || $p10) { - $result = six_format_infix( - six_get_op({ role => 'MULOP', meaning => 'times' }, 'inter-unit-product'), - undef, undef, - ($p2 ? Tokens(T_CS('\lx@power'), T_OTHER('2'), T_OTHER($p2)) : ()), - ($p10 ? Tokens(T_CS('\lx@power'), T_OTHER('10'), T_OTHER($p10)) : ()), - $result); } + if ($currPower) { + my $times = six_get_op({ role => 'MULOP', meaning => 'times' }, 'number-unit-product'); + my $prefix = { operator => 'exponent', arg2 => { integer => Tokenize($currPower) } }; + $result = six_format_infix($times, undef, undef, six_format_number($prefix), $result); } return $result; } # NOTE: This takes units as-is; is it feasable to guess at semantics? @@ -1133,6 +2176,8 @@ sub six_process_units { if (my $defns = six_convertUnits($expr)) { return six_format_units(six_parse_units($defns)); } else { + if (six_getBool('forbid-literal-units') && six_getBool('parse-units')) { + Error('unexpected', undef, undef, 'Literal units disabled'); } return six_parse_literalunits($expr); } } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1145,64 +2190,311 @@ DefMacro('\si OptionalKeyVals:SIX {}', sub { my $funits = six_wrap(six_process_units($units)); six_end_processing(); return $funits; }); +Let(T_CS('\unit'), T_CS('\si')); # \SI [options]{number}{units} +# \qty, \complexqty, and \qtyproduct also get Let to this +# This whole thing could be done better. It originally parsed and formatted the units +# then parsed and formatted the number. But the units can affect the number, +# depending on the options (and vice versa). So it would be better to parse both, use the +# options, and then format both. Or use the aforementioned options to change the +# number and units, and then pass it off to \num and \si. DefMacro('\SI OptionalKeyVals:SIX {}{}', sub { my ($gullet, $kv, $number, $units) = @_; six_begin_processing($gullet, $kv); # multi-part-units, product-units !!!! BLECH!!! - my $fnumber = six_format_number(six_parse_number($gullet, $number)); + my $parsedNumber = six_parse_number($gullet, $number); six_enableUnitMacros(1); - my $times = six_get_op({ role => 'MULOP', meaning => 'times' }, 'number-unit-product'); - my $result = six_wrap(six_format_infix($times, undef, undef, - $fnumber, I_wrap({}, six_process_units($units)))); + my $expr = ExpandPartially($units); # Apparently only partially here + my ($formattedUnits, $result); + if (my $defns = six_convertUnits($expr)) { + my @parsedUnits; + ($parsedNumber, @parsedUnits) = six_process_SI_units($defns, $parsedNumber); + $formattedUnits = six_format_units(@parsedUnits); + $result = six_format_SI($parsedNumber, $formattedUnits, $defns); } + else { + if (six_getBool('forbid-literal-units') && six_getBool('parse-units')) { + Error('unexpected', undef, undef, 'Literal units disabled'); } + $formattedUnits = six_parse_literalunits($expr); + $result = six_format_SI($parsedNumber, $formattedUnits); } six_end_processing(); return $result; }); +Let(T_CS('\qty'), T_CS('\SI')); +Let(T_CS('\complexqty'), T_CS('\SI')); +Let(T_CS('\qtyproduct'), T_CS('\SI')); + +sub six_get_num_terms { + my ($parsedNumber) = @_; + if (ref($parsedNumber) eq 'HASH' && $$parsedNumber{operator} && $$parsedNumber{operator} eq 'product') { + return six_get_num_terms($$parsedNumber{arg1}) + six_get_num_terms($$parsedNumber{arg2}); } + else { + return 1; } } + +sub six_process_SI_units { + my ($defns, $parsedNumber) = @_; + my $numTerms = six_get_num_terms($parsedNumber); + my $prefixMode = six_getChoice('prefix-mode'); + my $currPower = six_get_sci_exp($parsedNumber); + my $productUnits = six_getChoice('product-units'); + $productUnits =~ s/^brackets/bracket/; + $numTerms = 1 unless ($productUnits =~ /power$/); + my @parsedUnits = six_parse_units($defns); + + if ($numTerms > 1) { + foreach my $unit (@parsedUnits) { + if ($$unit{prepower}) { + my $oldExp = $$unit{prepower}{power}->toString; + $$unit{prepower} = { %{ LookupMapping('siunitx_macros', 'raiseto') } }; + $$unit{prepower}{power} = Tokenize($oldExp * $numTerms); } + elsif ($$unit{postpower}) { + my $oldExp = $$unit{postpower}{power}->toString; + $$unit{postpower} = { %{ LookupMapping('siunitx_macros', 'tothe') } }; + $$unit{postpower}{power} = Tokenize($oldExp * $numTerms); } + else { + $$unit{postpower} = { %{ LookupMapping('siunitx_macros', 'tothe') } }; + $$unit{postpower}{power} = Tokenize($numTerms); } } } + if ($prefixMode eq 'combine-exponent' && $currPower) { + # the power of 10 (or 2?) (if present) is absorbed into the first unit's prefix, modifying it + six_adjust_unit_prefix($parsedUnits[0], $currPower); + $parsedNumber = six_get_number_with_sci_exp($parsedNumber, $currPower); } + elsif ($prefixMode eq 'extract-exponent' || !six_getBool('prefixes-as-symbols')) { + # all prefixes are combined into a single common power of 10 or 2, at the front + # This option MODIFIES the units objects, extracts (removing) all prefixes + # Most complexity here is how to deal with "per", negative powers, and grouping of units + foreach my $unit (@parsedUnits) { + my $p = ToString($$unit{prepower}{power} || $$unit{postpower}{power} || 1) * ($$unit{per} ? -1 : +1); + if (my $pre = $$unit{prefix}) { + $currPower += $p * ToString($$pre{power}); } + delete $$unit{prefix}; + if (($$unit{unit}{name} || '') eq 'gram' && six_getBool('extract-mass-in-kilograms')) { # Special case: keep kilograms! + $$unit{prefix} = LookupMapping('siunitx_macros', 'kilo'); + $currPower -= 3 * $p; } } + if ($$parsedNumber{operator} && $$parsedNumber{operator} eq 'exponent') { + if ($currPower) { + $$parsedNumber{arg2}{sign} = T_OTHER('-') if ($currPower < 0); + $$parsedNumber{arg2}{integer} = Tokenize(abs($currPower)); } + else { + $$parsedNumber = $$parsedNumber{arg1}; } } + elsif ($currPower) { + my %exponent = (integer => Tokenize(abs($currPower))); + $exponent{sign} = T_OTHER('-') if ($currPower < 0); + $parsedNumber = { arg1 => $parsedNumber, arg2 => \%exponent, operator => 'exponent' }; } } + return ($parsedNumber, @parsedUnits); } + +sub six_format_SI { + my ($parsedNumber, $processedUnits, $defns) = @_; + my $result; + my $productUnits = six_getChoice('product-units'); + my $wrappedUnits = I_wrap({}, $processedUnits); + my $times = six_get_op({ role => 'MULOP', meaning => 'times' }, 'number-unit-product'); + if (ref($parsedNumber) eq 'HASH' && $$parsedNumber{operator} + && $$parsedNumber{operator} eq 'uncertain' && six_getChoice('separate-uncertainty-units') eq 'repeat') { + my $main = $$parsedNumber{arg1}; + my $fmain = six_format_number($main); + my @mainresult = six_format_infix($times, undef, undef, $fmain, $wrappedUnits); + my @uncertainties = @{ $$parsedNumber{arg2} }; + my @funcertainties = map { six_format_number($_) } @uncertainties; + my @uncertainResults = map { six_format_infix($times, undef, undef, $_, $wrappedUnits) } @funcertainties; + $result = six_wrap(six_format_infix(T_CS('\pm'), undef, undef, @mainresult, @uncertainResults)); } + else { + if (!six_getBool('parse-numbers') + || ($$parsedNumber{integer} && ToString($$parsedNumber{integer}) ne '1') + || (six_getBool('print-unity-mantissa')) + || $$parsedNumber{sign} || $$parsedNumber{decimal} || $$parsedNumber{fraction} || $$parsedNumber{operator}) { + if (ref($parsedNumber) eq 'HASH' && $$parsedNumber{operator} && $$parsedNumber{operator} eq 'product') { + my @terms = ($$parsedNumber{arg1}, $$parsedNumber{arg2}); + while ($terms[0]{operator} && $terms[0]{operator} eq 'product') { + my $arg1 = shift(@terms); + unshift(@terms, $$arg1{arg1}, $$arg1{arg2}); } + my @fterms; + if (six_getBool('exponent-to-prefix') && $defns) { + if (six_getBool('product-independent-prefix')) { + foreach my $parsedNum (@terms) { + my @units = six_parse_units($defns); # do this again + if (my $exp = six_get_sci_exp($parsedNum)) { + six_adjust_unit_prefix($units[0], $exp); + $parsedNum = six_get_number_with_sci_exp($parsedNum, $exp); } + my $funits = six_format_units(@units); + push(@fterms, six_format_infix($times, undef, undef, six_format_number($parsedNum), $funits)); } } + else { + my @units = six_parse_units($defns); + my $min_exp; + foreach my $parsedNum (@terms) { + my $next_exp = six_get_sci_exp($parsedNum); + if (!defined $min_exp || $next_exp < $min_exp) { + $min_exp = $next_exp; } } + @terms = map { six_get_number_with_sci_exp($_, $min_exp) } @terms; + six_adjust_unit_prefix($units[0], $min_exp); + my $funits = six_format_units(@units); + my @formatted = map { six_format_number($_); } @terms; + @fterms = map { six_format_infix($times, undef, undef, $_, $funits) } @formatted; } + $result = six_wrap(six_format_infix(six_get_op({ role => 'MULOP', meaning => 'times' }, 'output-product'), + undef, undef, @fterms)); } + else { + if ($productUnits eq 'repeat') { + @fterms = map { six_format_infix($times, undef, undef, six_format_number($_), $wrappedUnits) } @terms; } + else { + @fterms = map { six_format_number($_) } @terms; } + $result = six_wrap(six_format_infix(six_get_op({ role => 'MULOP', meaning => 'times' }, 'output-product'), + undef, undef, @fterms)); + if ($productUnits =~ /^bracket/) { + $result = six_wrap(six_get('product-open-bracket', 'open-bracket'), $result, + six_get('product-close-bracket', 'close-bracket')); } + $result = six_wrap(six_format_infix($times, undef, undef, $result, $wrappedUnits)) unless ($productUnits eq 'repeat'); } } + else { + my $fnumber = six_format_number($parsedNumber); + if (ref($parsedNumber) eq 'HASH' && $$parsedNumber{operator} + && $$parsedNumber{operator} eq 'uncertain' && six_getChoice('separate-uncertainty-units') eq 'bracket') { + $result = I_wrap({}, T_OTHER('('), $fnumber, T_OTHER(')')); } + else { + $result = $fnumber; } + $result = six_wrap(six_format_infix($times, undef, undef, $result, $wrappedUnits)); } } + else { + $result = six_wrap($wrappedUnits); } } + return $result; } + +# get a prefix corresponding to a given power (and base) +# if more than one prefix has that power, returns one of them arbitrarily +sub six_get_prefix_from_power { + my ($power, $base) = @_; + $base ||= 10; + my @units = LookupMappingKeys('siunitx_macros'); + foreach my $unit (@units) { + my $prefix = LookupMapping('siunitx_macros', $unit); + if ($$prefix{type} eq 'prefix' && $$prefix{base} == $base) { + my $prefixPower = ToString($$prefix{power}); + $prefixPower =~ s/\s+//g; + if ($prefixPower eq $power) { + return $prefix; } } } + Error('power', 'unknown', undef, "Exponent '$power' cannot be converted into a symbolic prefix (base $base)"); + return; } + +# adjust a unit according to a given exponential. modifies the unit in place. +sub six_adjust_unit_prefix { + my ($unit, $adjustment) = @_; + my $pre = $$unit{prefix}; + my $prePostPower = ToString(($$unit{prepower} && $$unit{prepower}{power}) + || ($$unit{postpower} && $$unit{postpower}{power}) || 1); + if ($pre) { + $adjustment += $prePostPower * ($$unit{per} ? -1 : 1) * ToString($$pre{power}); } + if ($adjustment) { + $adjustment /= $prePostPower * ($$unit{per} ? -1 : 1); + $$unit{prefix} = six_get_prefix_from_power($adjustment); } + else { + delete $$unit{prefix}; } + return; } # \SIlist[options]{number;number;...}{units} DefMacro('\SIlist OptionalKeyVals:SIX {}{}', sub { my ($gullet, $kv, $numbers, $units) = @_; six_begin_processing($gullet, $kv); - my $times = six_get_op({ role => 'MULOP', meaning => 'times' }, 'number-unit-product'); - my $mode = six_getChoice('list-units'); # brackets, repeat, single. - my @items = six_parse_numbers($gullet, $numbers); - @items = map { six_format_number($_); } @items; # Format (semantically) each number + my $times = six_get_op({ role => 'MULOP', meaning => 'times' }, 'number-unit-product'); + my $mode = six_getChoice('list-units'); # brackets, repeat, single. + my @parsed = six_parse_numbers($gullet, $numbers); + my ($result, $funits, @qtys, $defns); six_enableUnitMacros(1); - my $funits = six_process_units($units); - my $result; + my $expr = ExpandPartially($units); # Apparently only partially here - if ($mode eq 'repeat') { # make product of units with each number - $result = six_format_list(($mode eq 'brackets'), - map { six_format_infix($times, undef, undef, $_, $funits); } @items); } + if ($defns = six_convertUnits($expr)) { + $funits = six_format_units(six_parse_units($defns)); } + else { + if (six_getBool('forbid-literal-units') && six_getBool('parse-units')) { + Error('unexpected', undef, undef, 'Literal units disabled'); } + $funits = six_parse_literalunits($expr); } + + if ($mode eq 'repeat') { # make product of units with each number + if ($defns && six_getBool('exponent-to-prefix')) { + if (six_getBool('list-independent-prefix')) { + foreach my $parsedNum (@parsed) { + my @units = six_parse_units($defns); # do this again + if (my $exp = six_get_sci_exp($parsedNum)) { + six_adjust_unit_prefix($units[0], $exp); + $parsedNum = six_get_number_with_sci_exp($parsedNum, $exp); } + $funits = six_format_units(@units); + push(@qtys, six_format_infix($times, undef, undef, six_format_number($parsedNum), $funits)); } + $result = six_format_list(0, @qtys); } + else { + my @units = six_parse_units($defns); + my $min_exp = undef; + foreach my $parsedNum (@parsed) { + my $next_exp = six_get_sci_exp($parsedNum); + if (!defined $min_exp || $next_exp < $min_exp) { + $min_exp = $next_exp; } } + @parsed = map { six_get_number_with_sci_exp($_, $min_exp) } @parsed; + six_adjust_unit_prefix($units[0], $min_exp); + $funits = six_format_units(@units); + my @formatted = map { six_format_number($_); } @parsed; # Format (semantically) each number + $result = six_format_list(0, map { six_format_infix($times, undef, undef, $_, $funits); } @formatted); } } + else { + my @formatted = map { six_format_number($_); } @parsed; # Format (semantically) each number + $result = six_format_list(0, map { six_format_infix($times, undef, undef, $_, $funits); } @formatted); } } else { + my @formatted = map { six_format_number($_); } @parsed; # Format (semantically) each number $result = six_format_infix($times, undef, undef, - six_format_list(($mode eq 'brackets'), @items), $funits); } + six_format_list(scalar($mode =~ /^brackets?$/), @formatted), $funits); } $result = six_wrap($result); six_end_processing(); return $result; }); +Let(T_CS('\qtylist'), T_CS('\SIlist')); + +# if a number has the form {arg1, operator=>'exponent', arg2}, extract, parse, and return the exponent +sub six_get_sci_exp { + my ($parsedNum) = @_; + if (ref($parsedNum) eq 'HASH' && $$parsedNum{operator} && $$parsedNum{operator} eq 'exponent') { + return six_UnTeX($$parsedNum{arg2}) || 0; } + return 0; } # \SIrange[options]{number}{first}{last} DefMacro('\SIrange OptionalKeyVals:SIX {}{}{}', sub { my ($gullet, $kv, $first, $last, $units) = @_; six_begin_processing($gullet, $kv); - my $times = six_get_op({ role => 'MULOP', meaning => 'times' }, 'number-unit-product'); - my $mode = six_getChoice('range-units'); # brackets, repeat, single. - my $fnumber = six_format_number(six_parse_number($gullet, $first)); - my $lnumber = six_format_number(six_parse_number($gullet, $last)); + my $times = six_get_op({ role => 'MULOP', meaning => 'times' }, 'number-unit-product'); + my $mode = six_getChoice('range-units'); # brackets, repeat, single. + my @parsed = map { six_parse_number($gullet, $_) } ($first, $last); + my @formatted = map { six_format_number($_) } @parsed; six_enableUnitMacros(1); - my $result; - my $funits = six_process_units($units); + my ($result, $defns, $funits); + my $expr = ExpandPartially($units); # Apparently only partially here - if ($mode eq 'repeat') { # repeat the units on each number - $result = six_format_range(($mode eq 'brackets'), - six_format_infix($times, undef, undef, $fnumber, $funits), - six_format_infix($times, undef, undef, $lnumber, $funits)); } - else { # put the units after the range + if ($defns = six_convertUnits($expr)) { + $funits = six_format_units(six_parse_units($defns)); } + else { + if (six_getBool('forbid-literal-units') && six_getBool('parse-units')) { + Error('unexpected', undef, undef, 'Literal units disabled'); } + $funits = six_parse_literalunits($expr); } + + if ($mode eq 'repeat') { # repeat the units on each number + if (six_getBool('exponent-to-prefix')) { + @formatted = (); + if (six_getBool('range-independent-prefix')) { + foreach my $parsedNum (@parsed) { + my $exp = six_get_sci_exp($parsedNum); + $parsedNum = six_get_number_with_sci_exp($parsedNum, $exp); + my @units = six_parse_units($defns); # do this again + six_adjust_unit_prefix($units[0], $exp); + push(@formatted, six_format_infix($times, undef, undef, six_format_number($parsedNum), six_format_units(@units))); } + $result = six_format_range(0, @formatted); } + else { + my @exps = map { six_get_sci_exp($_) } @parsed; + my $min_exp = $exps[$exps[0] < $exps[1] ? 0 : 1]; + @parsed = map { six_get_number_with_sci_exp($_, $min_exp) } @parsed; + @formatted = map { six_format_number($_) } @parsed; + my @units = six_parse_units($defns); + six_adjust_unit_prefix($units[0], $min_exp); + $funits = six_format_units(@units); + my @infixed = map { six_format_infix($times, undef, undef, $_, $funits) } @formatted; + $result = six_format_range(0, @infixed); } } + else { + $result = six_format_range(0, + six_format_infix($times, undef, undef, $formatted[0], $funits), + six_format_infix($times, undef, undef, $formatted[1], $funits)); } } + else { # put the units after the range $result = six_format_infix($times, undef, undef, - six_format_range(($mode eq 'brackets'), $fnumber, $lnumber), $funits); } + six_format_range(scalar($mode =~ /brackets?/), @formatted), $funits); } $result = six_wrap($result); six_end_processing(); return $result; }); +Let(T_CS('\qtyrange'), T_CS('\SIrange')); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1277,6 +2569,7 @@ DefPrimitive('\DeclareSIPrefix OptionalKeyVals:SIX SkipSpaces DefToken {}{}', su DefMacroI($newcs, undef, '\lx@six@unitobject@collapsible{' . $name . '}{' . ToString($presentation) . '}'); return; }); + # \NewDocumentCommand \DeclareSIPrePower { m m } { # \__siunitx_declare_power_before:Nn #1 {#2} } # Prefix operator, applies a power @@ -1305,11 +2598,19 @@ DefPrimitive('\DeclareSIPostPower OptionalKeyVals:SIX SkipSpaces DefToken {}', s DefMacroI($newcs, undef, '\lx@six@unitobject{' . $name . '}'); return; }); +DefMacro('\DeclareSIPower DefToken DefToken {}', sub { + my ($gullet, $csPre, $csPost, $power) = @_; + return Tokens(T_CS('\DeclareSIPrePower'), $csPre, T_BEGIN, $power, T_END, + T_CS('\DeclareSIPostPower'), $csPost, T_BEGIN, $power, T_END); }); + # Special builtins: \tothe{}, \raiseto{} AssignMapping('siunitx_macros', tothe => { name => 'tothe', cs => T_CS('\tothe'), implementation => T_CS('\lx@six@tothe'), keyvals => undef, type => 'postpower', arg => 'power', presentation => T_SUPER }); -DefMacro('\lx@six@tothe{}', '\lx@six@unitobject@arg{tothe}{#1}'); +#DefMacro('\lx@six@tothe{}', '\lx@six@unitobject@arg{tothe}{#1}'); +DefMacro('\lx@six@tothe{}', sub { + my ($gullet, $arg) = @_; + return Invocation(T_CS('\lx@six@unitobject@arg'), 'tothe', $arg); }); AssignMapping('siunitx_macros', raiseto => { name => 'raiseto', cs => T_CS('\raiseto'), implementation => T_CS('\lx@six@raiseto'), @@ -1332,8 +2633,35 @@ DefPrimitive('\DeclareSIQualifier OptionalKeyVals:SIX SkipSpaces DefToken {}', s # Special builtin: \of{} AssignMapping('siunitx_macros', of => { name => 'of', cs => T_CS('\of'), implementation => T_CS('\lx@six@of'), - keyvals => undef, type => 'qualifier', arg => 'qualifier', presentation => T_CS('\mathrm') }); + keyvals => undef, type => 'qualifier', arg => 'qualifier', presentation => T_CS('\lx@six@of@aux') }); +# todo delete comments +# presentation should be T_CS('\lx@six@of@aux') +# presentation => Tokens() +# and \lx@six@of should become \lx@six@unitobject@arg{of}. But then it doesn't get the next argument DefMacro('\lx@six@of{}', '\lx@six@unitobject@arg{of}{#1}'); +#DefMacro('\lx@six@of{}', '\lx@six@of@aux {#1}'); + +# todo delete this? +DefMacro('\lx@six@of@aux {}', sub { + my ($gullet, $arg) = @_; + # this is usually too late - the group for the \si or \SI has closed + my $qmode = six_get('qualifier-mode')->toString; + $qmode =~ s/s$//; + return Invocation(T_CS('\lx@six@of@' . $qmode), $arg); }); +DefMacro('\lx@six@of@subscript{}', sub { + my ($gullet, $arg) = @_; + return Tokens(T_SUB, T_BEGIN, T_CS('\mathrm'), T_BEGIN, $arg, T_END, T_END); + #return Tokens(six_get('text-subscript-command'), T_BEGIN, $arg, T_END); + # switch to this once #2781 fixed +}); +DefMacro('\lx@six@of@bracket{}', sub { + my ($gullet, $arg) = @_; + Tokens(six_get('open-bracket'), Invocation(T_CS('\mathrm'), $arg), six_get('close-bracket')); }); +DefMacro('\lx@six@of@combine{}', '\mathrm{#1}'); +DefMacro('\lx@six@of@phrase{}{}', sub { + my ($gullet, $qual, $phrase) = @_; + Tokens($phrase, Invocation(T_CS('\mathrm'), $qual)); }); +DefMacro('\lx@six@of@space{}', '\;\mathrm{#1}'); # \NewDocumentCommand \DeclareSIUnit { O {} m m } { # \__siunitx_declare_unit:Nnn #2 {#3} {#1} } @@ -1344,6 +2672,20 @@ DefPrimitive('\DeclareSIUnit OptionalKeyVals:SIX SkipSpaces DefToken {}', sub { my ($stomach, $kv, $cs, $presentation) = @_; my $name = $cs->getCSName; $name =~ s/^\\//; my $newcs = T_CS('\lx@six@' . $name); + # siunitx no longer allows prefixes without units. The recommended alternative is + # \DeclareSIUnit\noop{\relax} + # This becomes the xml + # + # + # + # and then the html + # + # noop + # + # we can fix this by replacing the $presentation, but we have to know when to do so + # \char, \text, and the various \SIUnitSymbol commands are Primitives, but they're ok + # explicitly looking for \relax feels hacky, but gets the job done + $presentation = Tokenize('') if ($presentation->equals(Tokenize('\relax'))); AssignMapping('siunitx_macros', $name => { name => $name, cs => $cs, implementation => $newcs, keyvals => $kv, type => 'unit', presentation => $presentation }); @@ -1375,7 +2717,7 @@ AssignMapping('siunitx_macros', DefMacro('\lx@six@highlight{}', '\lx@six@unitobject@arg{highlight}{#1}'); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -# Tables +# Tables - \lx@six@initialize also sets up column types passed to the key table-column-type (default S) DefColumnType('s Optional', sub { my ($gullet, $kv) = @_; $LaTeXML::BUILD_TEMPLATE->addColumn( @@ -1387,17 +2729,6 @@ DefColumnType('s Optional', sub { ); return; }); -DefColumnType('S Optional', sub { - my ($gullet, $kv) = @_; - $LaTeXML::BUILD_TEMPLATE->addColumn( - before => Tokens(T_BEGIN, - T_CS('\lx@si@column@prep'), ($kv ? (T_OTHER('['), $kv, T_OTHER(']')) : ()), - T_CS('\lx@SI@column@parse')), - after => Tokens(T_CS('\lx@si@column@end'), T_END), - # align => 'char:' . ToString(Digest(T_CS('\nprt@decimal')))); - ); - return; }); - DefMacro('\lx@si@column@prep OptionalKeyVals:SIX', sub { my ($gullet, $kv) = @_; six_begin_processing($gullet, $kv); @@ -1412,14 +2743,26 @@ DefPrimitive('\lx@si@column@end', ''); # color treated a bit differently? DefMacro('\lx@SI@column@parse XUntil:\lx@si@column@end', sub { - my ($gullet, $number) = @_; - my @tokens = $number->unlist; + my ($gullet, $entry) = @_; + my @tokens = $entry->unlist; my $doparse = six_getBool('parse-numbers'); + if (six_getBool('table-auto-round')) { + AssignValue('SIX_round-precision' => six_get('table-figures-decimal')); + AssignValue('SIX_round-mode' => Tokenize('places')); } # Deal with recognizing "surrounding material" - my @pre = (); - my @post = (); - my $color = six_get('color'); - my $result; + my ($result, @pre, @post, $save_trimright); # , $pretoks, $posttoks + $save_trimright = @tokens && Equals($tokens[-1], T_CS('\lx@column@trimright')); + if ($save_trimright) { + pop(@tokens); + pop(@tokens) while (@tokens && Equals($tokens[-1], T_SPACE)); } + my $color = six_get('number-color'); + # todo upgrade - just delete these 4 lines? + #($pretoks, @tokens) = six_peel_group(@tokens); + #($posttoks, @tokens) = six_peel_tail_group(@tokens); + #push(@pre, T_BEGIN, $pretoks->unlist, T_END) if $pretoks; + #unshift(@post, T_BEGIN, $posttoks->unlist, T_END) if $posttoks; + # move spaces, commands, and groups from the table entry to @pre or @post + # this may fail if \command{arg} doesn't bracket an argument while (@tokens) { my $cc = $tokens[0]->getCatcode; if (($cc == CC_SPACE) @@ -1434,21 +2777,75 @@ DefMacro('\lx@SI@column@parse XUntil:\lx@si@column@end', sub { push(@pre, T_BEGIN, $p, T_END); } else { last; } } - # six_parse_begin($gullet, $kv); - if ($doparse) { + while (@tokens) { # move spaces and commands from the table entry to @post + my $cc = $tokens[-1]->getCatcode; + if (($cc == CC_SPACE) + || ($doparse && ($cc == CC_CS) + && !six_match1($tokens[-1], 'input-protect-tokens', 'input-symbols'))) { + unshift(@post, pop(@tokens)); } + elsif ($doparse && $cc == CC_END) { + my $p; + ($p, @tokens) = six_peel_tail_group(@tokens); + unshift(@post, T_BEGIN, $p, T_END); } + else { + last; } } + my ($pad_left, $pad_right) = ('', ''); + if ($doparse and @tokens) { my $tokens = [six_apply_mathligatures(@tokens)]; my $parsed = six_match_number($tokens); - @post = @$tokens; # Save what's left - $result = six_format_number(six_postprocess($parsed)); } + if (@pre || six_get('table-space-text-pre')) { + my $prewidth = Digest(six_get('table-space-text-pre') || '')->getWidth->[0]; + @pre = (T_CS('\makebox'), ExplodeText('[' . $prewidth . 'sp][r]'), T_BEGIN, @pre, T_END); } + if (@post || six_get('table-space-text-post')) { + my $postwidth = Digest(six_get('table-space-text-post') || '')->getWidth->[0]; + @post = (T_CS('\makebox'), ExplodeText('[' . $postwidth . 'sp][l]'), T_BEGIN, @post, T_END); } + if (@$tokens) { + # how does siunitx tell that something isn't a number? + #Error('unexpected', undef, undef, 'Unexpected tokens remain in table cell'); + unshift(@post, @$tokens); } +# we pass references to pad_left / right so that we can update them and have that pass back up the recursion + $result = $parsed + ? six_format_number(six_postprocess($parsed), bracket => 0, pad_left_ref => \$pad_left, pad_right_ref => \$pad_right, + in_table_number => (six_getChoice('table-alignment-mode') ne 'none')) + : (); } else { $result = Tokens(@tokens); } + if ($pad_left) { + my $spacing = six_table_space($pad_left); + if (six_getBool('table-align-text-before')) { + push(@pre, $spacing); } + else { + unshift(@pre, $spacing); } } + if ($pad_right) { + my $spacing = six_table_space($pad_right); + if (six_getBool('table-align-text-after')) { + unshift(@post, $spacing); } + else { + push(@post, $spacing); } } if ($color) { push(@pre, T_BEGIN, T_CS('\color'), T_BEGIN, $color, T_END); unshift(@post, T_END); } + # get this before closing the group in end_postprocessing + # but it's not used, because alignment is set when the column is initially parsed + # todo upgrade delete? + #my $align = six_getChoice('table-'.(@tokens?'number':'text').'-alignment'); six_end_processing(); - return Tokens(@pre, - ($result ? six_wrap($result) : ()), - @post); }); + push(@post, T_SPACE, T_CS('\lx@column@trimright')) if ($save_trimright); + if (@tokens) { + $result = Tokens(@pre, six_wrap($result), @post); + # todo upgrade delete? + # if ( @pre && $pre[0]->getCatcode == CC_BEGIN && ! $color ) { + # $result = Tokens(@pre, six_wrap($result, @post)); } + # else { + # $result = six_wrap(@pre?@pre:(), $result, @post?@post:()); } + } + else { + $result = Tokens(@pre, $result, @post); } + return $result; + # todo upgrade delete + #return @tokens ? six_wrap($result) : $result; + #return Tokens(@pre, ( $result && @{$result} ? six_wrap($result) : ()), @post); +}); # similar to \si DefMacro('\lx@si@column@parse XUntil:\lx@si@column@end', sub { @@ -1456,7 +2853,7 @@ DefMacro('\lx@si@column@parse XUntil:\lx@si@column@end', sub { my @tokens = $units->unlist; my @pre = (); my @post = (); - my $color = six_get('color'); + my $color = six_get('color', 'unit-color'); my $result; while (@tokens) { @@ -1473,6 +2870,8 @@ DefMacro('\lx@si@column@parse XUntil:\lx@si@column@end', sub { if (my $defns = six_convertUnits(Tokens(@tokens))) { $result = six_format_units(six_parse_units($defns)); } else { + if (six_getBool('forbid-literal-units') && six_getBool('parse-units')) { + Error('unexpected', undef, undef, 'Literal units disabled'); } ## Info('unexpected', 'whatever', undef, ## "Don't yet know how to parse non-macro unit expressions"); $result = Tokens(@tokens); } @@ -1484,93 +2883,86 @@ DefMacro('\lx@si@column@parse XUntil:\lx@si@column@end', sub { ($result ? six_wrap($result) : ()), @post); }); -# ? -#Let('\tablenum', '\lx@table@num'); -Let('\tablenum', '\num'); - #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% RawTeX(<<'EoTeX'); + \sisetup{ abbreviations, - binary-units, + binary-units , - math-rm = \mathrm, - math-sf = \mathsf, - math-tt = \mathtt, - mode = math, + math-rm = \mathrm , + math-sf = \mathsf , + math-tt = \mathtt , + mode = math , text-rm = \rmfamily, text-sf = \sffamily, text-tt = \ttfamily, input-product = x, input-quotient = /, -%( + input-open-uncertainty = (, input-close-uncertainty = ), input-complex-roots = ij, input-comparators = {<=>\approx\ge\geq\gg\le\leq\ll\sim}, input-decimal-markers = {.,}, input-digits = 0123456789, input-exponent-markers = dDeE, - input-open-uncertainty = (, % ) input-protect-tokens = \approx\dots\ge\geq\gg\le\leq\ll\mp\pi\pm\sim, input-signs = +-\mp\pm, input-symbols = \dots\pi, input-uncertainty-signs = \pm, - add-decimal-zero = true, add-integer-zero = true, retain-unity-mantissa = true, - round-half = up, - round-minimum = 0, - round-precision = 2, + round-half = up , + round-minimum = 0 , + round-precision = 2 , - bracket-numbers = true , % ( + bracket-numbers = true , + open-bracket = ( , close-bracket = ) , complex-root-position = after-number , copy-decimal-marker = false , exponent-base = 10 , exponent-product = \times , - group-digits = true , + group-digits = all , group-minimum-digits = 5 , group-separator = \, , - open-bracket = ( , % ) ( + output-open-uncertainty = ( , output-close-uncertainty = ) , output-complex-root = \ensuremath { \mathrm { i } } , output-decimal-marker = . , - output-open-uncertainty = (, % ) fraction-function = \frac , output-product = \times , output-quotient = / , parse-numbers = true , - quotient-mode = symbol, - + quotient-mode = symbol , forbid-literal-units = false, - parse-units = true, + parse-units = true , prefixes-as-symbols = true, - bracket-unit-denominator = true, - inter-unit-product = \,, - literal-superscript-as-power = true, - per-mode = reciprocal, - per-symbol = /, - power-font = number, - qualifier-mode = subscript, - qualifier-phrase = { ~ of ~ }, + bracket-unit-denominator = true , + inter-unit-product = \, , + literal-superscript-as-power = true , + per-mode = power , % same behavior of v2 recipricol + per-symbol = / , + power-font = number , + qualifier-mode = subscript , multi-part-units = brackets, number-unit-product = \, , - product-units = repeat, + product-units = repeat , list-final-separator = { and } , list-pair-separator = { and } , - list-separator = {, } , - list-units = repeat, + list-separator = {, } , + list-units = repeat , range-phrase = { to }, - range-units = repeat, + range-units = repeat , table-unit-alignment = center, @@ -1581,10 +2973,7 @@ RawTeX(<<'EoTeX'); table-align-uncertainty = true, table-omit-exponent = false, table-parse-only = false, - table-number-alignment = center-decimal-marker, table-text-alignment = center, - table-figures-decimal = 2, - table-figures-integer = 3, redefine-symbols = true, @@ -1599,8 +2988,7 @@ RawTeX(<<'EoTeX'); text-angstrom = \AA, text-arcminute = \ensuremath { { } ^ { \prime } }, text-arcsecond = \ensuremath { { } ^ { \prime \prime } }, - text-celsius = - \ensuremath { { } ^ { \circ } } \kern -\scriptspace C , + text-celsius = \ensuremath { { } ^ { \circ } } \kern -\scriptspace C , text-degree = \ensuremath { { } ^ { \circ } }, text-micro = \c__siunitx_mu_tl , text-ohm = \ensuremath { \c__siunitx_omega_tl }, @@ -1614,26 +3002,23 @@ RawTeX(<<'EoTeX'); % multi-part-units = brackets, % parse-numbers = true, % parse-units = true, -% product-units = repeat, % otherwise - bracket-numbers , +% bracket-numbers , detect-family , detect-italic , detect-mode , detect-shape , detect-weight , multi-part-units , - parse-numbers , - parse-units , - product-units, +% parse-numbers , +% parse-units , number-angle-product=, number-angle-separator=, arc-separator=, } -\DeclareSIUnit \kilogram { \kilo \gram } -%%%\DeclareSIUnit \metre { m } -%%%\DeclareSIUnit \meter { \metre } +%%%\DeclareSIUnit \metre { m } +%%%\DeclareSIUnit \meter { \metre } %%% Swapped to be more NIST consistent. \DeclareSIUnit \meter { m } \DeclareSIUnit \metre { \meter } @@ -1643,6 +3028,8 @@ RawTeX(<<'EoTeX'); \DeclareSIUnit \kelvin { K } \DeclareSIUnit \candela { cd } \DeclareSIUnit \gram { g } +\DeclareSIPrefix \quecto { q } { -30 } +\DeclareSIPrefix \ronto { r } { -27 } \DeclareSIPrefix \yocto { y } { -24 } \DeclareSIPrefix \zepto { z } { -21 } \DeclareSIPrefix \atto { a } { -18 } @@ -1664,6 +3051,9 @@ RawTeX(<<'EoTeX'); \DeclareSIPrefix \exa { E } { 18 } \DeclareSIPrefix \zetta { Z } { 21 } \DeclareSIPrefix \yotta { Y } { 24 } +\DeclareSIPrefix \ronna { R } { 27 } +\DeclareSIPrefix \quetta { Q } { 30 } +\DeclareSIUnit \kilogram { \kilo \gram } \DeclareSIUnit \becquerel { Bq } \DeclareSIUnit \celsius { \SIUnitSymbolCelsius } \DeclareSIUnit \degreeCelsius { \SIUnitSymbolCelsius } @@ -1688,46 +3078,31 @@ RawTeX(<<'EoTeX'); \DeclareSIUnit \watt { W } \DeclareSIUnit \weber { Wb } \DeclareSIUnit [ number-unit-product = ] \arcmin { \arcminute } -\DeclareSIUnit [ number-unit-product = ] - \arcminute { \SIUnitSymbolArcminute } -\DeclareSIUnit [ number-unit-product = ] - \arcsecond { \SIUnitSymbolArcsecond } +\DeclareSIUnit [ number-unit-product = ] \arcminute { \SIUnitSymbolArcminute } +\DeclareSIUnit [ number-unit-product = ] \arcsecond { \SIUnitSymbolArcsecond } \DeclareSIUnit \day { d } \DeclareSIUnit[ number-unit-product = ] \degree { \SIUnitSymbolDegree } \DeclareSIUnit \hectare { ha } \DeclareSIUnit \hour { h } -\DeclareSIUnit \litre { l } -\DeclareSIUnit \liter { L } +\DeclareSIUnit \litre { l } % siunitx uses L +\DeclareSIUnit \liter { L } % siunitx uses \litre \DeclareSIUnit \minute { min } \DeclareSIUnit \percent { \char 37 } \DeclareSIUnit \tonne { t } -\DeclareSIUnit \astronomicalunit { ua } +\DeclareSIUnit \astronomicalunit { au } \DeclareSIUnit \atomicmassunit { u } \DeclareSIUnit \electronvolt { eV } \DeclareSIUnit \dalton { Da } - -%\group_begin: -%\cs_set_eq:NN \endgroup \group_end: -%\char_set_catcode_math_subscript:N \_ -%\use:n -% { -% \endgroup - \DeclareSIUnit \clight { \text { \ensuremath { c _ { 0 } } } } - \DeclareSIUnit \electronmass - { \text { \ensuremath { m _ { \textup { e } } } } } -% } -\DeclareSIUnit \planckbar { \text { \ensuremath { \hbar } } } +\DeclareSIUnit \clight { \text { \( c \sb { 0 } \) } } +%\DeclareSIUnit \clight { \text { \ensuremath { c \char_generate:nn { `\_ } { 8 } { 0 } } } } +\DeclareSIUnit \electronmass { \text { \( m \sb { \textup { e } } \) } } +%\DeclareSIUnit \electronmass { \text { \ensuremath { m \char_generate:nn { `\_ } { 8 } { \textup { e } } } } } +\DeclareSIUnit \planckbar { \text { \ensuremath { \hbar } } } \DeclareSIUnit \elementarycharge { \text { \ensuremath { e } } } -%\group_begin: -%\cs_set_eq:NN \endgroup \group_end: -%\char_set_catcode_math_subscript:N \_ -%\use:n -% { -% \endgroup - \DeclareSIUnit \bohr { \text { \ensuremath { a _ { 0 } } } } - \DeclareSIUnit \hartree - { \text { \ensuremath { E _ { \textup { h } } } } } -% } +\DeclareSIUnit \bohr { \text { \( a \sb { 0 } \) } } +%\DeclareSIUnit \bohr { \text { \ensuremath { a \char_generate:nn { `\_ } { 8 } { 0 } } } } +\DeclareSIUnit \hartree { \text { \( E \sb { \textup { h } } \) } } +%\DeclareSIUnit \hartree { \text { \ensuremath { E \char_generate:nn { `\_ } { 8 } { \textup { h } } } } } \DeclareSIUnit \angstrom { \SIUnitSymbolAngstrom } \DeclareSIUnit \bar { bar } \DeclareSIUnit \barn { b } @@ -1742,8 +3117,126 @@ RawTeX(<<'EoTeX'); \DeclareSIPrePower \cubic { 3 } \DeclareSIPostPower \cubed { 3 } +\DeclareSIUnit \nW { \nano \watt } +\DeclareSIUnit \nF { \nano \farad } +\DeclareSIUnit \uF { \micro \farad } +\DeclareSIUnit \mF { \milli \farad } +\DeclareSIUnit \H { \henry } +\DeclareSIUnit \fH { \femto \henry } +\DeclareSIUnit \pH { \pico \henry } +\DeclareSIUnit \nH { \nano \henry } +\DeclareSIUnit \uH { \micro \henry } +\DeclareSIUnit \mH { \milli \henry } +\DeclareSIUnit \nC { \nano \coulomb } +\DeclareSIUnit \uC { \micro \coulomb } +\DeclareSIUnit \mC { \milli \coulomb } +\DeclareSIUnit \C { \coulomb } +\DeclareSIUnit \uT { \micro \tesla } +\DeclareSIUnit \mT { \milli \tesla } +\DeclareSIUnit \T { \tesla } + +\sisetup{ + % 4.2 printing + number-mode = math , + reset-math-version = true , + reset-text-family = true , + reset-text-series = true , + reset-text-shape = true , + text-subscript-command = \textsubscript , + text-superscript-command = \textsuperscript, + unit-mode = math , + % 4.3 parsing numbers (input-uncertainty-divider below) + expression = #1 , + % 4.4 post-processing numbers (exponent-thresholds below) + add-decimal-zero = true , + drop-zero-decimal = false , + exponent-mode = input , + fixed-exponent = 0 , + minimum-integer-digits = 0 , + minimum-decimal-digits = 0 , + round-direction = nearest, + round-mode = none , + round-pad = true , + round-zero-positive = true , + uncertainty-round-direction = nearest, + % 4.5 printing numbers + bracket-ambiguous-numbers = true , + digit-group-size = 3 , + digit-group-first-size = 3 , + digit-group-other-size = 3 , + print-zero-integer = true , + print-unity-mantissa = true , + uncertainty-descriptor-mode = bracket-separator, + uncertainty-descriptor-separator = ~ , % regular space because expl3 + uncertainty-separator =, + uncertainty-mode = compact , + zero-symbol = {\mbox{---}} , + % 4.6 + list-open-bracket = ( , + list-close-bracket = ) , + list-exponents = individual , + product-open-bracket = ( , + product-close-bracket = ) , + product-exponents = individual , + product-mode = symbol , + product-phrase = { \text{by} }, + product-symbol = \times , + range-open-bracket = ( , + range-close-bracket = ) , + range-exponents = individual , + % 4.7 + complex-angle-unit = degrees , + complex-mode = input , + complex-phase-command = \angle , + complex-symbol-degree = \SIUnitSymbolDegree, %\degree, + input-complex-root = ij , + % 4.8 + angle-mode = input, + angle-symbol-degree = \degree, + angle-symbol-minute = \arcminute, + angle-symbol-second = \arcsecond, + % 4.10 + fraction-command = \frac, + per-symbol-script-correction = \!, + unit-font-command = \mathrm, + % 4.11 + extract-mass-in-kilograms = true, + prefix-mode = input, + quantity-product = \,, + separate-uncertainty-units = bracket, + % 4.12 + table-align-text-after = true, + table-align-text-before = true, + table-alignment = center, + table-column-width = 0pt, + table-format=2.2, + % 4.14: preamble only + list-input-separator = ;, + product-input-separator = x, + table-column-type = S, +} + +% can't seem to get :_12 in expl3 +% : becomes :_11 +% \c_colon_str becomes the \cs_16 +% \char_generate:nn { `: } { 12 } becomes the 11 item token list +\sisetup{ + % 4.3 parsing numbers + input-uncertainty-divider =:, + % 4.4 post-processing numbers + exponent-thresholds ={-3:3}, + % these don't exist in siunitx, but using them simplifies our code + angle-input-separator =;, + complex-angle-separator =:, + exponent-threshold-separator =:, +} +%\sisetup{table-format=2.2} + EoTeX +AssignValue('SIX_retain-explicit-decimal-marker' => Tokenize($VERSION_TWO ? 'true' : 'false')); +AssignValue('SIX_qualifier-phrase' => Tokenize($VERSION_TWO ? 'of' : '')); + sub six_load_compat1 { RawTeX(<<'EoTeX'); \DeclareSIPrePower \Square { 2 } diff --git a/lib/LaTeXML/Util/Test.pm b/lib/LaTeXML/Util/Test.pm index 43be8d555..4c8359ab2 100644 --- a/lib/LaTeXML/Util/Test.pm +++ b/lib/LaTeXML/Util/Test.pm @@ -31,6 +31,9 @@ sub latexml_tests { if ($options{texlive_min} && (texlive_version() < $options{texlive_min})) { plan skip_all => "Requirement minimal texlive $options{texlive_min} not met."; return done_testing(); } + if ($options{texlive_max} && ($options{texlive_max} < texlive_version() )) { + plan skip_all => "Requirement maximal texlive $options{texlive_max} not met."; + return done_testing(); } if (!opendir($DIR, $directory)) { # Can't read directory? Fail (assumed single) test. return do_fail($directory, "Couldn't read directory $directory:$!"); } @@ -86,6 +89,7 @@ sub check_requirements { next unless $reqmts; my @required_packages = (); my $texlive_min = 0; + my $texlive_max = 0; my $required_env; if (!(ref $reqmts)) { @required_packages = ($reqmts); } @@ -94,7 +98,8 @@ sub check_requirements { elsif (ref $reqmts eq 'HASH') { @required_packages = (ref $$reqmts{packages} eq 'ARRAY' ? @{ $$reqmts{packages} } : $$reqmts{packages}); $required_env = $$reqmts{env}; - $texlive_min = $$reqmts{texlive_min} || 0; } + $texlive_min = $$reqmts{texlive_min} || 0; + $texlive_max = $$reqmts{texlive_max} || 0; } foreach my $reqmt (@required_packages) { if (pathname_kpsewhich($reqmt) || pathname_find($reqmt)) { } else { @@ -108,6 +113,11 @@ sub check_requirements { diag("Skip: $message"); skip($message, $ntests); return 0; } + if ($texlive_max && ($texlive_max < texlive_version() )) { + my $message = "Maximal texlive $texlive_max requirement not met for $test"; + diag("Skip: $message"); + skip($message, $ntests); + return 0; } elsif ($required_env && !$ENV{$required_env}) { my $message = "$test is only checked in continuous integration. (use make test CI=true)"; diag("Skip: $message"); diff --git a/t/80_complex.t b/t/80_complex.t index 901d04a18..a2f84e5a6 100644 --- a/t/80_complex.t +++ b/t/80_complex.t @@ -13,4 +13,19 @@ latexml_tests("t/complex", texlive_min => 2021}, si => { env=>'CI', # only runs in continuous integration - packages => 'siunitx.sty', texlive_min => 2015 } }); + packages => 'siunitx.sty', texlive_min => 2022 }, # should be 2015 + si_preamble => { + env=>'CI', # only runs in continuous integration + packages => 'siunitx.sty', texlive_min => 2015 }, + siV2 => { + env=>'CI', # only runs in continuous integration + packages => 'siunitx.sty', texlive_min => 2015, texlive_max => 2020 }, + # siV3 is triggered if \fmtversion >= 2021, + # lib/LaTeXML/Engine/latex_base.pool.ltxml sets \fmtversion to 2018/12/01 + # if `make formats` is called, blib/lib/LaTeXML/Engine/latex_dump.pool.ltxml + # overrides it to the actual value + # GitHub actions call `make formats` only for 2023 onward + # this also means `make test CI=true` will fail without `make formats` + siV3 => { + env=>'CI', # only runs in continuous integration + packages => 'siunitx.sty', texlive_min => 2023 } }); diff --git a/t/complex/si.pdf b/t/complex/si.pdf index d7fa36ff4..802b48068 100644 Binary files a/t/complex/si.pdf and b/t/complex/si.pdf differ diff --git a/t/complex/si.tex b/t/complex/si.tex index f94d9c5cb..2aa1ab8d0 100644 --- a/t/complex/si.tex +++ b/t/complex/si.tex @@ -1,10 +1,17 @@ \documentclass{article} + +%\usepackage[binary-units]{siunitx}[=v2] +\usepackage{siunitx} + \usepackage{xcolor} \usepackage{cancel} -\usepackage{siunitx} -\usepackage{float} \usepackage{multirow} +%\usepackage{sansmath} % not in LaTeXML + \usepackage{booktabs} +\usepackage{etoolbox} + +\usepackage{hyperref} \DeclareSIQualifier\polymer{pol} \DeclareSIQualifier\catalyst{cat} @@ -22,44 +29,64 @@ \def\mabbra{a} \DeclareSIUnit\mabbrb{\mabbra} -\DeclareSIPrefix\killer{\kilo}{3} +\DeclareSIPrefix\killer{k}{3} +% so six_get_prefix_from_power(3) -> \killer, not \kilo +% but they have the same abbreviation, so it works out + +\DeclareSIUnit\noop{\relax} + +\DeclareSIPower\quartic\tothefourth{4} -\usepackage{amsmath} \begin{document} + +{\sloppy +\tableofcontents +} + +\section{Introduction} + +This tries to follow the package documentation released 2025-07-09, with additional tests. Items remaining (generally ordered from hardest to easiest) are +\begin{itemize} +\item error: evaluate-expression, expression % 4 occurrences +\item sansmath: package needed to evaluate two more tests +\item The spacing in tables is not quite right. See the comment on \&six\_table\_space +\item font and spacing: several instances where we should make a font change or adjust the spacing, but don't. % 10 of each +\item detect if loaded with \verb|[=v2]| or \verb|[=2021-04-09]| or earlier % see issue 2719 +\end{itemize} + +\section{siunitx for the impatient} +\num{12345,67890}\\ +\num{.3e45}\\ +\complexnum{1+-2i}\\ +\numproduct{1.654 x 2.34 x 3.430} + +\unit{kg.m.s^{-1}} \\ +\unit{\kilogram\metre\per\second} \\ +\unit[per-mode = symbol]{\kilogram\metre\per\second} \\ +\unit[per-mode = symbol]{\kilogram\metre\per\ampere\per\second} + +\numlist{10;20;30} \\ +\qtylist{0.13;0.67;0.80}{\milli\metre} \\ +\numrange{10}{20} \\ +\qtyrange{0.13}{0.67}{\milli\metre} + +\subsection*{Other tests} %\ang{1.2e10;2 x 3;4} +\numlist{10 ; 20 ; 30} \\ \ang{1.2;3;4} -{ -\color{red} -Some text \\ -\SI{4}{\metre\per\sievert} \\ -More text \\ -\SI[color = blue]{4}{\metre\per\sievert} \\ -Still red here! -\numlist[color = blue]{1;2;3;4}\\ -Still red here!\\ -} Unsemantic: -\si{m^2.s}\\ -\si{\mu m^2}\\ +\unit{m^2.s}\\ +\unit{\mu m^2} Semantic again: -\SI{0.094}{\pi . \milli\meter . \milli\radian}\\ +\qty{0.094}{\pi . \milli\meter . \milli\radian}\\ +\qty{0.094}{\frac{1}{3} . \milli\meter . \milli\radian}\\ +\qty{0.094}{\pi \per \milli\meter . \milli\radian\tothe{3}} -\SI{0.094}{\frac{1}{3} . \milli\meter . \milli\radian}\\ +\section{Using the siunitx package} -\SI{0.094}{\pi \per \milli\meter . \milli\radian\tothe{3}}\\ -\section{Numbers} -\subsection{General} -%\num{\sqrt{2}}\\ -%\num{{a word}}\\ -\num{12345,67890}\\ -\num{1+-2i}\\ -\num{.3e45}\\ -\num{1.654 x 2.34 x 3.430}\\ -\num{\pi}\\ -\num{2\pi}\\ -\num{\pi/3}\\ +\subsection{Numbers} \num{123}\\ \num{1234}\\ @@ -68,101 +95,818 @@ \subsection{General} \num{0,1234}\\ \num{.12345}\\ \num{3.45d-4}\\ -\num{-e10}\\ +\num{-e10} + +\numlist{10;30;50;70} + +\numproduct{10 x 30} + +\numrange{10}{30} + +\subsubsection{Other Tests} \num{123e4}\\ %\num{123e4(3)}\\ -\num{123(3)e4}\\ +\num{123(3)e4} \num{123\pm2}\\ -\num{123\pm2i}\\ -\num{123+234i}\\ +\complexnum{123\pm2i}\\ +\complexnum{123+234i}\\ +\complexnum{123(1)+234(1)ie3}\\ +\complexnum{234(1)ie3} %\num{123+234}\\ %\num{123e2+234e3i}\\ -\num{123+234ie3}\\ -\num{123(1)+234(1)ie3}\\ -%\num{123e2(1)+234e3i(1)}\\ -%\num{+234(1)ie3}\\ %comes out weird? -\num{+3i}\\ -\num{+3ie4}\\ + +\def\dig{1234} +\def\odd{\xi} +\def\odder{\odd} Pretty nonsensical stuff? -\num{1.\pi e+3}\\ -\def\dig{1234}\\ +\num[parse-numbers=false]{1.\pi e+3}\\ \num{\dig.\dig}\\ -\def\odd{\xi}\\ -\def\odder{\odd}\\ -\num[input-symbols=\xi]{3\xi}\\ -\num[input-symbols=\xi]{3\odd}\\ -%\num[input-symbols=\odd]{3\odd}\\ -\num[input-symbols=\odd, input-protect-tokens=\odd]{3\odd}\\ -\num[input-symbols=\odd, input-protect-tokens=\odd]{3\odder}\\ -\num[input-symbols=\odder, input-protect-tokens=\odder]{3\odder}\\ -%\num[input-symbols=\odder, input-protect-tokens=\odd]{3\odder}\\ -%\num[input-symbols=\odd, input-protect-tokens=\odder]{3\odder}\\ +\num[input-digits=\xi,parse-numbers=false]{3\xi}\\ +\num[input-digits=\xi,parse-numbers=false]{3\odd}\\ +%\num[input-digits=\odd]{3\odd}\\ +\num[input-digits=\odd, parse-numbers=false]{3\odd}\\ +\num[input-digits=\odd, parse-numbers=false]{3\odder}\\ +\num[input-digits=\odder, parse-numbers=false]{3\odder} \num{1.23(1)}\\ %\num{1.23(0.01)} \num{1.23\pm0.01}\\ %\num{1.23(1.0)}\\ %\num{1.23(\pm1)}\\ -\num{1.23(\pi)}\\ +\num[parse-numbers=false]{1.23(\pi)} + +\num[parse-numbers=false]{1.234(5) x \pi} \\ +\num[uncertainty-mode = separate, parse-numbers=false]{1.234(5) x \pi} + +\subsubsection{Lists and ranges of numbers} + +\qtylist{10;30;45}{\metre}\\ +\qtyproduct{10 x 30 x 45}{\metre}\\ +\qtyrange{10}{30}{\metre} + +\subsection{Angles} + +\ang{10} \\ +\ang{12.3} \\ +\ang{4,5} \\ +\ang{1;2;3} \\ +\ang{;;1} \\ +\ang{+10;;} \\ +\ang{-0;1;} + +\subsection{Units} + +\subsubsection{unit} +\unit{kg.m/s^2} \\ +\unit{g_{polymer}~mol_{cat}.s^{-1}} \\ +\unit{\kilo\gram\metre\per\square\second} \\ +\unit{\gram\per\cubic\centi\metre} \\ +\unit{\square\volt\cubic\lumen\per\farad} \\ +\unit{\metre\squared\per\gray\cubic\lux} \\ +\unit{\henry\second} + +\subsubsection{qty} +\qty[mode = text]{1.23}{J.mol^{-1}.K^{-1}} \\ +\qty{.23e7}{\candela} \\ +\qty[per-mode = symbol]{1.99}{\per\kilogram} \\ +\qty[per-mode = fraction]{1,345}{\coulomb\per\mole} + +\subsubsection{qtylist} +\qtylist{10;30;45}{\metre} + +\subsubsection{qtyproduct} +\qtyproduct{10 x 30 x 45}{\metre} + +\subsubsection{qtyrange} +\qtyrange{10}{30}{\metre} + + +\subsection{Complex numbers and quantities} + +\complexnum{123+234ie3}\\ +\complexnum{123(1)+234(1)ie3}\\ +%\num{123e2(1)+234e3i(1)}\\ +%\num{+234(1)ie3}\\ %comes out weird? +\complexnum{+3i}\\ +\complexnum{+3ie4} + +\subsection{The unit macros} +\newcommand{\showunit}[1]{#1 & \texttt{\Backslash#1} & \unit{\csname#1\endcsname}} + +The SI base units: +\begin{center} +\begin{tabular}{lll}\toprule +Unit & Macro & Symbol \\\midrule +\showunit{ampere}\\ +\showunit{candela}\\ +\showunit{kelvin}\\ +\showunit{kilogram}\\ +\showunit{metre}\\ +\showunit{mole}\\ +\showunit{second}\\\bottomrule +\end{tabular} +\end{center} + +The coherent derived units: +\begin{center} +\begin{tabular}{@{}llc llc@{}}\toprule +Unit & Macro & Symb & +Unit & Macro & Symb \\\cmidrule(r){1-3}\cmidrule(l){4-6} +\showunit{becquerel} & \showunit{newton} \\ +\showunit{degreeCelsius} & \showunit{ohm} \\ +\showunit{coulomb} & \showunit{pascal} \\ +\showunit{farad} & \showunit{radian} \\ +\showunit{gray} & \showunit{siemens} \\ +\showunit{hertz} & \showunit{sievert} \\ +\showunit{henry} & \showunit{steradian} \\ +\showunit{joule} & \showunit{tesla} \\ +\showunit{katal} & \showunit{volt} \\ +\showunit{lumen} & \showunit{watt} \\ +\showunit{lux} & \showunit{weber} \\\bottomrule +\end{tabular} +\end{center} + +The non-SI units: +\begin{center} +\begin{tabular}{lll}\toprule +Unit & Macro & Symbol \\\midrule +\showunit{astronomicalunit}\\ +\showunit{bel}\\ +\showunit{dalton}\\ +\showunit{day}\\ +\showunit{decibel}\\ +\showunit{degree}\\ +\showunit{electronvolt}\\ +\showunit{hectare}\\ +\showunit{hour} \\ +\showunit{litre}\\ +\showunit{liter}\\ +\showunit{arcminute}\\ +\showunit{minute}\\ +\showunit{arcsecond}\\ +\showunit{neper}\\ +\showunit{tonne}\\\bottomrule +\end{tabular} +\end{center} + +%\ExplSyntaxOn +% this accesses siunitx internals, and may therefore break +\newcommand{\showprefix}[1]{ + #1 & \texttt{\Backslash#1} & \unit{ \csname #1\endcsname \noop } & + \qty[prefix-mode=extract-exponent, print-unity-mantissa=false]{1}{\csname#1\endcsname\noop}% +% the following +% \str_if_eq:nnTF { #1 } { micro } { -6 } { \__ltxml_power_from_text:n { #1 } } +% works in LaTeX, but not LaTeXML (b/c it doesn't have the internals) +} +%\cs_new:Npn \__ltxml_prefix_from_text:n #1 { +% \use:c { __siunitx_unit_ \token_to_str:c { #1 } :w } +%} +%\cs_new:Npn \__ltxml_power_from_prefix:n #1 { +% \prop_get:NeNTF +% \l__siunitx_unit_prefixes_forward_prop +% { #1 } +% \l_tmpa_tl +% { \l_tmpa_tl } +% { \qty [ prefix-mode=extract-exponent, print-unity-mantissa=false ] { 1 } { \use:c { #1 } \noop } } +%} +%\cs_new:Npn \__ltxml_power_from_text:n #1 { +% { +% \bool_set_false:N \l__siunitx_unit_test_bool +% \bool_set_false:N \l__siunitx_unit_parsing_bool +% \exp_args:Ne \__ltxml_power_from_prefix:n { \__ltxml_prefix_from_text:n { #1 } } +% } +%} +%\__ltxml_prefix_from_text:n { kibi } +%\ExplSyntaxOff + +SI prefixes: +\begin{center} +\begin{tabular}{@{}llcl llcl@{}}\toprule +Prefix & Cmd & Symb & Power & +Prefix & Cmd & Symb & Power \\\cmidrule(r){1-4}\cmidrule(l){5-8} +\showprefix{quecto} & \showprefix{deca}\\ +\showprefix{ronto} & \showprefix{hecto}\\ +\showprefix{yocto} & \showprefix{kilo}\\ +\showprefix{zepto} & \showprefix{mega}\\ +\showprefix{atto} & \showprefix{giga}\\ +\showprefix{femto} & \showprefix{tera}\\ +\showprefix{pico} & \showprefix{peta}\\ +\showprefix{nano} & \showprefix{exa}\\ +\showprefix{micro} & \showprefix{zetta}\\ +\showprefix{milli} & \showprefix{yotta}\\ +\showprefix{centi} & \showprefix{ronna}\\ +\showprefix{deci} & \showprefix{quetta}\\\bottomrule +\end{tabular} +\end{center} + +\unit{\square\becquerel} \\ +\unit{\joule\squared\per\lumen} \\ +\unit{\cubic\lux\volt\tesla\cubed} \\ +\unit{\henry\tothe{5}} \\ +\unit{\raiseto{4.5}\radian} \\ +\unit{\joule\per\mole\per\kelvin} \\ +\unit{\joule\per\mole\kelvin} \\ +\unit{\per\henry\tothe{5}} \\ +\unit{\per\square\becquerel} \\ +\unit{\kilogram\of{metal}} \\ +\qty[qualifier-mode = bracket]{0.1}{\milli\mole\of{cat}\per\kilogram\of{prod}} \\ +\unit[per-mode = fraction]{\cancel\kilogram\metre\per\cancel\kilogram\per\second} \\ +\unit{\highlight{red}\kilogram\metre\per\second} \\ +\unit[unit-color = purple]{\highlight{blue}\kilogram\metre\per\second} % todo font + +\subsection{Unit abbreviations} + +Abbreviated units + +\begin{center} +\newcommand{\showunitabbrev}[4]{#1#3 & \texttt{\Backslash#2#4} & \unit{\csname#2#4\endcsname}} +\ExplSyntaxOn +\newcommand{\showunitabbrevs}[3]{ +% \midrule + \clist_map_variable:nNn { #3 } { \l_tmpa_tl } { + \exp_after:wN \showunitabbrev \l_tmpa_tl { #1 } { #2 } \\ + } +} +\ExplSyntaxOff +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{gram}{g}{{femto}{f},{pico}{p},{nano}{n},{micro}{u},{milli}{m},{}{},{kilo}{k}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{metre}{m}{{pico}{p},{nano}{n},{micro}{u},{milli}{m},{centi}{c},{deci}{d},{}{},{kilo}{k}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{meter}{m}{{pico}{p},{nano}{n},{micro}{u},{milli}{m},{centi}{c},{deci}{d},{}{},{kilo}{k}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{second}{s}{{atto}{a},{femto}{f},{pico}{p},{nano}{n},{micro}{u},{milli}{m},{}{}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{mole}{mol}{{femto}{f},{pico}{p},{nano}{n},{micro}{u},{milli}{m},{}{},{kilo}{k}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{ampere}{A}{{pico}{p},{nano}{n},{micro}{u},{milli}{m},{}{},{kilo}{k}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{litre}{l}{{micro}{u},{milli}{m},{}{},{hecto}{h}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{liter}{L}{{micro}{u},{milli}{m},{}{},{hecto}{h}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{hertz}{Hz}{{milli}{m},{}{},{kilo}{k},{mega}{M},{giga}{G},{tera}{T}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{newton}{N}{{milli}{m},{}{},{kilo}{k},{mega}{M}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{pascal}{Pa}{{}{},{kilo}{k},{mega}{M},{giga}{G}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{ohm}{ohm}{{milli}{m},{kilo}{k},{mega}{M}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{volt}{V}{{pico}{p},{nano}{n},{micro}{u},{milli}{m},{}{},{kilo}{k}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{watt}{W}{{nano}{n},{micro}{u},{milli}{m},{}{},{kilo}{k},{mega}{M},{giga}{G}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{joule}{J}{{micro}{u},{milli}{m},{}{},{kilo}{k}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{electronvolt}{eV}{{milli}{m},{}{},{kilo}{k},{mega}{M},{giga}{G},{tera}{T}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{watt hour}{Wh}{{kilo}{k}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{farad}{F}{{femto}{f},{pico}{p},{nano}{n},{micro}{u},{milli}{m},{}{}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{henry}{H}{{femto}{f},{pico}{p},{nano}{n},{micro}{u},{milli}{m},{}{}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{coulomb}{C}{{nano}{n},{micro}{u},{milli}{m},{}{}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{tesla}{T}{{micro}{u},{milli}{m},{}{}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{kelvin}{K}{{}{}} +\bottomrule +\end{tabular} + +\begin{tabular}{lcc}\toprule +Unit & Abbreviation & Symbol \\\midrule +\showunitabbrevs{bel}{B}{{deci}{d}} +\bottomrule +\end{tabular} +\end{center} + +Binary prefixes: +\newcounter{tablerow} +\begin{center} +% the documentation numbers are hardcoded in +% /usr/local/texlive/YYYY/texmf-dist/source/latex/siunitx/siunitx.tex +% the powers are not stored in siunitx. see siunitx-binary.dtx +\newcommand{\showBinaryPrefix}[1]{% + \stepcounter{tablerow}% + #1 & \texttt{\Backslash#1} & \unit{\csname #1\endcsname\noop} & \arabic{tablerow}0 +} +\begin{tabular}{cccc}\toprule +Prefix & Command & Symbol & Power \\\midrule +\showBinaryPrefix{kibi} \\ +\showBinaryPrefix{mebi} \\ +\showBinaryPrefix{gibi} \\ +\showBinaryPrefix{tebi} \\ +\showBinaryPrefix{pebi} \\ +\showBinaryPrefix{exbi} \\ +\showBinaryPrefix{zebi} \\ +\showBinaryPrefix{yobi} \\\bottomrule +\end{tabular} +\end{center} + +\subsection{Creating new macros} + +\qty{67890}{\degree} \\ +\qty[quantity-product = \,]{67890}{\degree} + +\unit{\kilogram\tothefourth}\\ +\unit{\quartic\metre} + +\qty{1.234}{\gram\polymer\per\mole\catalyst\per\hour} + +\subsubsection{Other Tests} +% Note that \kilogram is defined as \kilo\gram, and acts sorta like a macro +\unit{\kilogram} +\unit{\kilo\gram} +% Not allowed. +%\unit{\kilo\kilogram} +%\unit{\kilo\kilo\gram} +{ +% and note that regular macros ARE expanded! +\def\killermeater{\kilo\meter} +\unit{\killermeater} +} +{ +% BUT, it prefers its OWN definitions! +\def\gram{Grr} +\unit{\kilo\gram} +} + +% However, it's happy with various indirect definitions. +% Ie. units, prefixes (at least) act like regular macros within \si. +\unit{\abbra}\\ +\unit{\abbrb}\\ +\unit{\abbrc}\\ +\unit{\abbrd}\\ +\unit{\abbre} + +\unit{\mabbra}\\ +\unit{\mabbrb} + +\unit{\killer\meter} + +% Where can highlight go? +\unit{\highlight{red}\kilo\gram\metre\per\second} \\ +\unit{\kilo\highlight{red}\gram\metre\per\second} \\ +\unit{\kilo\gram\highlight{red}\metre\per\second} \\ +\unit{\kilo\gram\metre\highlight{red}\per\second} \\ +\unit{\kilo\gram\metre\per\highlight{red}\second} + +\unit{\cancel\kilo\gram\metre\per\second} \\ +\unit{\kilo\cancel\gram\metre\per\second} \\ +\unit{\kilo\gram\cancel\metre\per\second} \\ +\unit{\kilo\gram\metre\cancel\per\second} \\ +\unit{\kilo\gram\metre\per\cancel\second} + + +\subsection{Tabular material} + +Standard behaviour of the \texttt{S} column type +\begin{center} +\begin{tabular}{S} +\toprule +{Some Values} \\ +\midrule +2.3456 \\ +34.2345 \\ +-6.7835 \\ +90.473 \\ +5642.5 \\ +1.2e3 \\ +e4 \\ +\bottomrule +\end{tabular} +\end{center} + +Detection of surrounding material in an \texttt{S} column +\begin{center} +\begin{tabular}{S[color=orange]} +\toprule +{Some Values} \\ +\midrule +12.34 \\ +\color{purple} 975,31 \\ +44.268 \textsuperscript{\emph{a}} \\ +\bottomrule +\end{tabular} +\end{center} + +Text before and after numbers +\begin{center} +\sisetup{table-format = {now }2.4{\textsuperscript{\emph{a}}}} +\begin{tabular}{@{}S@{}} +\toprule +{Values} \\ +\midrule +2.3456 \\ +34.2345 \textsuperscript{\emph{a}}\\ +34.2345 {\textsuperscript{\emph{a}}}\\ +56.7835 \\ +%now~ 90.473 \\ % todo error +{now~} 90.473 \\ % todo incorrect +\bottomrule +\end{tabular} +\end{center} + +Controlling complex alignment with the tablenum macro +\begin{center} +\begin{tabular}{lr} +\toprule +Heading & Heading \\ +\midrule +Info & More info \\ +Info & More info \\ +\multicolumn{2}{c}{\tablenum[table-format = 4.4]{12,34}} \\ +\multicolumn{2}{c}{\tablenum[table-format = 4.4]{333.5567}} \\ +\multicolumn{2}{c}{\tablenum[table-format = 4.4]{4563.21}} \\ +\bottomrule +\end{tabular} +\qquad +\begin{tabular}{lr} +\toprule +Heading & Heading \\ +\midrule +\multirow{2}*{\tablenum{88,999}} & aaa \\ +& bbb \\ +\multirow{2}*{\tablenum{33,435}} & ccc \\ +& ddd \\ +\bottomrule +\end{tabular} +\end{center} + +\section{Package control options} + +\stepcounter{subsection} + +\subsection{Printing} +\subsubsection{mode, number-mode, unit-mode} +\subsubsection{reset-text-[family\textbar series\textbar shape]} % todo font +{ + \sisetup{mode = text} + {\itshape \num{1234}}\\ + {\bfseries \num{1234}}\\ + {\sffamily \num{1234}}\\ + \sisetup{ + reset-text-family = false , + reset-text-series = false , + reset-text-shape = false + } + {\itshape \num{1234}}\\ + {\bfseries \num{1234}}\\ + {\sffamily \num{1234}} +} + +\subsubsection{propagate-math-font, reset-math-version} +{ + {\boldmath \unit{\kilogram}}\\ % todo font + %{\sansmath $\unit{\kilogram}$}\\ % todo usepackage sansmath + {$\mathsf{\unit{\kilogram}}$}\\ + \sisetup{ + propagate-math-font = true , + reset-math-version = false + } + {\boldmath \unit{\kilogram}}\\ + %{\sansmath $\unit{\kilogram}$}\\ % todo usepackage sansmath + {$\mathsf{\unit{\kilogram}}$} +} + +\subsubsection{text-[family\textbar series]-to-math} % todo font +{ + {\sffamily \unit{\kilogram}}\\ + {\bfseries $\unit{\kilogram}$}\\ + \sisetup{ + text-family-to-math = true , + text-series-to-math = true + } + {\sffamily \unit{\kilogram}}\\ + {\bfseries $\unit{\kilogram}$} +} + +\subsubsection{text-font-command} +{ + \sisetup{number-mode = text} + \qty{123456789}{\kilo\volt\per\centi\metre} \\ + \sisetup{text-font-command = \fontfamily{pplx}\selectfont} + \qty{123456789}{\kilo\volt\per\centi\metre} % todo font +} + +\subsubsection{text-[sub\textbar super]script-command} +{ + \sisetup{unit-mode = text} + \unit{\kg\of{polymer}} \\ + \newcommand*\mysubscript[1]{\textsubscript{\textcolor{blue}{#1}}} + \newcommand\mysuperscript[1]{\textsuperscript{\textcolor{green}{#1}}} + \sisetup{text-subscript-command = \mysubscript} + \unit{\kg\of{polymer}} % todo font +} + +\subsubsection{color, number-color, unit-color} % todo font +{ + \color{red}% + Some text \\ + \qty{4}{\kilogram} \\ + More text \\ + \qty[color = blue]{4}{\kilogram} \\ + \qty[number-color = blue]{4}{\kilogram} \\ + \qty[unit-color = blue]{4}{\kilogram} \\ + Still red here! +} + +\qty[number-color=blue,color=green]{1}{\gram} \\ +\qty[color=green,number-color=blue]{1}{\gram} \\ +\qty[unit-color=blue,color=green]{1}{\gram} \\ +\qty[color=green,unit-color=blue]{1}{\gram} \\ +\ang[number-color=green,unit-color=blue]{-1;2;3} \\ +\numlist{1;2;3}\\ +\numproduct[product-mode=phrase]{1x2}\\ +\numrange{1}{2} + +\numproduct{1.234(5) x 6.78(9)} \subsection{Parsing numbers} -\subsubsection{input-digits, input-decimal-markers, input-signs, input-exponent-markers} +%\subsubsection{input-digits, input-decimal-markers, input-signs, input-exponent-markers} +\subsubsection{input-digits, input-ignore} +\num[input-ignore=3a\pi]{1a234\pi5} -\subsubsection{input-symbols, input-ignore} \subsubsection{input-comparators} \num{< 10} \\ -%\SI{>> 5}{\metre} \\ -\num{\le 0.12}\\ +\qty{>> 5}{\metre} \\ +\num{\le 0.12} -\subsubsection{input-open-uncertainty, input-close-uncertainty, input-uncertainty-signs} +\subsubsection{input-[open\textbar close]-uncertainty, input-uncertainty-signs} \num{9.99(9)}\\ \num{9.99 +- 0.09}\\ \num{9.99 \pm 0.09}\\ \num{123 +- 4.5}\\ \num{12.3 +- 6}\\ +\num{123.4(12)} \\ +\num{123.4(1.2)}\\ +\num{123.4(12)(45)} \\ +\num{123.4 \pm 1.2 \pm 4.5} -\subsubsection{input-complex-roots} -\num{9.99 + 88.8i} \\ -\num{9.99 + i88.8}\\ +\subsubsection{input-uncertainty-divider} +\num{10.56(12:34)} \\ +\num{123.4(4.6:7.8)}\\ +\num{10.56(1:2)(3)}\\ +\num{6.45(2)(3:4)} + +Also:\\ +\num{5.6(1.2:3.4)} \\ +\num{78.56(12:34)} \\ +\num{123.4(12)(45)(67)} \\ +\num{123.4 \pm 1.2 \pm 4.5 \pm 6.7} -\subsubsection{input-protect-tokens} \subsubsection{parse-numbers} \num[parse-numbers = false]{\sqrt{2}}\\ +\qty[parse-numbers = false]{\sqrt{3}}{\metre} + +\subsubsection*{Other tests} +\num[parse-numbers=false]{\pi}\\ +\num[parse-numbers=false]{2\pi}\\ +\num[parse-numbers=false]{\pi/3} + +% todo error +%\subsubsection{evaluate-expression, expression} +%{ +%\sisetup{evaluate-expression}% +%\qty{2 + 4 * 3}{\joule} \\ +%\qty[expression = 10 * (#1)]{2 + 4 * 3}{\joule} +%} + +\subsubsection{retain-explicit-decimal-marker, retain-explicit-plus, retain-negative-zero, retain-zero-uncertainty} +%\num[retain-explicit-decimal-marker]{10.} \\ % v2 or v3 +\num{+345} \\ +\num[retain-explicit-plus]{+345} \\ +\num{-0} \\ +\num[retain-negative-zero]{-0} \\ +\num{12.3(0)} \\ +\num[retain-zero-uncertainty]{12.3(0)} + +{ +\num{456} \\ +\num{.789} \\ +\sisetup{ + add-decimal-zero = false, + add-integer-zero = false, +}% +\num{456} \\ +\num{.789} % v2: .789; v3: 0.789. But add-integer-zero is v2 +} \subsection{Post-processing numbers} -\subsubsection{round-mode, round-precision} + +\subsubsection{exponent-mode, fixed-exponent} +{ +\num{0.001} \\ +\num{0.0100} \\ +\num{1200} \\ +\sisetup{exponent-mode = scientific}% +\num{0.001} \\ +\num{0.0100} \\ +\num{1200} \\ +\sisetup{exponent-mode = engineering}% +\num{0.001} \\ +\num{0.0100} \\ +\num{1200} \\ +\sisetup{ +exponent-mode = fixed, +fixed-exponent = 2, +}% +\num{0.001} \\ +\num{0.0100} \\ +\num{1200} \\ +} +\num{1.23e4} \\ +\num[exponent-mode = fixed, fixed-exponent = 0]{1.23e4} + +\complexnum[exponent-mode=engineering]{0.5+1000i} +% todo tex has (0.000 500+1.000i)x10^3 (see siunitx#813) + +\subsubsection{exponent-thresholds} +This is unique to version 3. + +\subsubsection{drop-exponent, drop-uncertainty} +\num{0.01(2)} \\ +\num[drop-uncertainty]{0.01(2)} \\ +\num{0.01e3} \\ +\num[drop-exponent]{0.01e3} % causes warning: Potentially ambiguous dropping of exponent + +\subsubsection{round-mode, round-precision, round-pad} + { \num{1.23456} \\ \num{14.23} \\ \num{0.12345(9)} \\ +\num{0.0012345}\\ \sisetup{ round-mode = places, round-precision = 3 }% +places:\\ \num{1.23456} \\ \num{14.23} \\ \num{0.12345(9)} \\ +\num{0.0012345}\\ \sisetup{ round-mode = figures, round-precision = 3 }% +figures:\\ \num{1.23456} \\ \num{14.23} \\ -\num{0.12345(9)}\\ +\num{0.12345(9)} \\ +\num{9999}\\ +\num{0.0012345}\\ +\sisetup{ +round-mode = uncertainty, +round-precision = 1 +}% +uncertainty:\\ +\num{0.12345(9)} \\ +\num{0.12345(23)} \\ +\num{0.12345(234)}\\ +\num{12345(123)}\\ +\num{123.456(012)}\\ +\num{1234.5(12.3)}\\ +\num{1234.56(98)}\\ +\num{9.99(99)}\\ +\num{99.99(999)}\\ +}% +{ +\sisetup{round-mode = figures, round-precision = 4}% +figures:\\ +\num{12.3} \\ +\num{012.34} \\ +\num[round-pad = false]{12.3}\\ +} +Also\\ +\numproduct[round-mode=places]{.123 x .456 x .789} + +\subsubsection{round-direction, round-half} +{ +\sisetup{round-mode = places} +\num{0.054} \\ +\num{0.046} \\ +\sisetup{round-direction = down}% +\num{0.054} \\ +\num{0.046} \\ +\sisetup{round-direction = up}% +\num{0.054} \\ +\num{0.046} \\ +} +{ +\sisetup{ +round-mode = figures, +round-precision = 1, +round-half = up +}% +\num{0.055} \\ +\num{0.045} \\ +\sisetup{round-half = even}% +\num{0.055} \\ +\num{0.045} } -\subsubsection{round-integer-to-decimal} + +\subsubsection{uncertainty-round-direction} { -\num[round-mode = figures]{1} \\ -\num[round-mode = places]{1} \\ -\sisetup{round-integer-to-decimal} -\num[round-mode = figures]{1} \\ -\num[round-mode = places]{1}\\ +\sisetup{round-mode = uncertainty} +\num{0.123(41)} \\ +\sisetup{uncertainty-round-direction = up}% +\num{0.123(41)} \\ % lets try again +\sisetup{round-precision=1}% +\num{0.123(41)} } \subsubsection{round-minimum} @@ -170,251 +914,535 @@ \subsubsection{round-minimum} \sisetup{round-mode = places}% \num{0.0055} \\ \num{0.0045} \\ +\num{-0.0045} \\ \sisetup{round-minimum = 0.01}% \num{0.0055} \\ -\num{0.0045}\\ +\num{0.0045} \\ +\num{-0.0045}\\ +\sisetup{round-minimum = {0,01}}% +\num{0,0045} } -\subsubsection{round-half} +\subsubsection{round-zero-positive} { -\sisetup{round-mode = places, round-half = up}% -\num{0.055} \\ -\num{0.045} \\ -\sisetup{round-half = even}% -\num{0.055} \\ -\num{0.045} +\sisetup{round-mode = places}% +\num{-0.001} \\ +\sisetup{round-zero-positive = false}% +\num{-0.001} } -\subsubsection{add-decimal-zero, add-integer-zero} +\subsubsection{drop-zero-decimal} +\num{2.0} \\ +\num{2.1} \\ { -\num{123.} \\ -\num{456} \\ -\num{.789} \\ -\sisetup{ - add-decimal-zero = false, - add-integer-zero = false, -}% -\num{123.} \\ -\num{456} \\ -\num{.789}\\ +\sisetup{drop-zero-decimal}% +\num{2.0} \\ +\num{2.1} } -\subsubsection{minimum-integer-digits} +\subsubsection{minimum-decimal-digits, minimum-integer-digits} \num{123} \\ -\num[minimum-integer-digits = 1]{123} \\ \num[minimum-integer-digits = 2]{123} \\ -\num[minimum-integer-digits = 3]{123} \\ -\num[minimum-integer-digits = 4]{123}\\ - -\subsubsection{explicit-sign, retain-explicit-plus} -\num{+345} \\ -\num[retain-explicit-plus]{+345} \\ -\num[explicit-sign = -]{345}\\ -\num[explicit-sign = -]{+345}\\ - -\subsubsection{retain-unity-mantissa, retain-zero-exponent} -\num{1e4} \\ -\num[retain-unity-mantissa = false]{1e4} \\ -\num{444e0} \\ -\num[retain-zero-exponent = true]{444e0}\\ +\num[minimum-integer-digits = 4]{123} \\ +\num{0.123} \\ +\num[minimum-decimal-digits = 2]{0.123} \\ +\num[minimum-decimal-digits = 4]{0.123} -\subsubsection{scientific-notation, fixed-exponent} +\subsubsection{Other Tests} { -\num{0.001}\\ -\num{0.0100} \\ -\num{1200}\\ -\sisetup{scientific-notation = true}% -\num{0.001}\\ -\num{0.0100} \\ -\num{1200}\\ -\sisetup{scientific-notation = engineering}% -\num{0.001}\\ -\num{0.0100} \\ -\num{1200}\\ +\num{001} \\ +%\num{123.} \\ % v2 or v3 +\num{456} \\ +\num{.789} \\ \sisetup{ -fixed-exponent = 2, -scientific-notation = fixed, + minimum-decimal-digits = 0, + print-zero-integer = false, }% -\num{0.001}\\ -\num{0.0100} \\ -\num{1200}\\ +%\num{123.} \\ % v2 or v3 +\num{456} \\ +\num{.789} \\ } +Also: \\ +\num[minimum-decimal-digits=2]{1} \\ +\num[minimum-decimal-digits=1, drop-zero-decimal]{1.00} \\ +\num[minimum-decimal-digits=2, drop-zero-decimal]{1} -\subsubsection{omit-uncertainty} -\num{0.01(2)} \\ -\num[omit-uncertainty]{0.01(2)}\\ - -\subsection{Printing numbers} -\subsubsection{group-digits, group-four-digits,group-seperator} -\num{12345.67890}\\ -\num[group-digits= false]{12345.67890}\\ -\num[group-digits= decimal]{12345.67890} \\ -\num[group-digits= integer]{12345.67890}\\ +% an example from https://github.com/josephwright/siunitx/issues/756 +\num[separate-uncertainty=true, round-mode=uncertainty, drop-zero-decimal=true, round-precision=1]{-52.01(43)} -\num[group-digits= false]{12345.67890}\\ -\num[group-digits= decimal]{12345.67890} \\ -\num[group-digits= integer]{12345.67890}\\ - -\num{1234567890.1234567890}\\ -\num[group-four-digits]{1234567890.1234567890}\\ +\subsection{Printing Numbers} +\subsubsection{group-digits, group-separator} +\num{12345.67890} \\ +\num[group-digits = none]{12345.67890} \\ +\num[group-digits = decimal]{12345.67890} \\ +\num[group-digits = integer]{12345.67890}\\ \num{12345} \\ \num[group-separator = {,}]{12345} \\ \num[group-separator = \text{~}]{12345}\\ +\num[group-separator = \ ]{12345} \subsubsection{group-minimum-digits} \num{1234} \\ +\num{12345} \\ +\num[group-minimum-digits = 5]{1234} \\ +\num[group-minimum-digits = 5]{12345} \\ +\num{1234.5678} \\ +\num{12345.67890} \\ +\num[group-minimum-digits = 5]{1234.5678} \\ +\num[group-minimum-digits = 5]{12345.67890} + +\subsubsection*{Other tests} +\num{1234} \\ \num[group-minimum-digits = 4]{1234} \\ \num{1234.5678} \\ -\num[group-minimum-digits = 4]{1234.5678}\\ +\num[group-minimum-digits = 4]{1234.5678} -\subsubsection{output-complex-root,output-decimal-marker,copy-complex-root,copy-decimal-marker} -\num{1.23} \\ -\num[output-decimal-marker = {,}]{1.23} \\ -\num{1+2i} \\ -\num[output-complex-root = \text{\ensuremath{i}}]{1+2i} \\ -\num[output-complex-root = j]{1+2i} \\ -\num[copy-complex-root]{1+2j} \\ -\num[copy-decimal-marker]{555,555}\\ +\subsubsection{digit-group-size, digit-group-first-size, digit-group-other-size} +\num{1234567890} \\ +\num[digit-group-size = 5]{1234567890} \\ +\num[digit-group-other-size = 2]{1234567890} -\subsubsection{complex-root-position} -\num{67-0.9i} \\ -\num[complex-root-position = before-number]{67-0.9i} \\ -\num[complex-root-position = after-number]{67-0.9i}\\ +\subsubsection*{Other tests} +\num{1234567890.1234567890}\\ +\num[digit-group-size=4]{1234567890.1234567890}\\ +\num[digit-group-size = 5, digit-group-other-size = 2]{1234567890} \\ +\num[digit-group-other-size = 2, digit-group-size = 5]{1234567890} \\ +\num[digit-group-size = 5, digit-group-first-size = 2]{1234567890} \\ +\num[digit-group-first-size = 2, digit-group-size = 5]{1234567890} + +\subsubsection{output-decimal-marker} +\num{1.23} \\ +\num[output-decimal-marker = {,}]{1.23} % todo spacing: the , gets interpreted as punctuation \subsubsection{exponent-base, exponent-product} \num[exponent-product = \times]{1e2} \\ \num[exponent-product = \cdot]{1e2} \\ -\num[exponent-base = 2]{1e2}\\ +\num[exponent-base = 2]{1e2} \subsubsection{output-exponent-marker} +\num[output-exponent-marker = e]{1e2} \\ \num[output-exponent-marker = \text{e}]{1e2} \\ -\num[output-exponent-marker = \ensuremath{\mathrm{E}}]{1e2}\\ +\num[output-exponent-marker = \mathrm{E}]{1e2}\\ +\num[output-exponent-marker = \ensuremath{\mathrm{E}}]{1e2} -\subsubsection{separate-uncertainty,uncertainty-separator,output-open-uncertainty,output-close-uncertainty} +\subsubsection{uncertainty-[mode\textbar separator], output-[open\textbar close]-uncertainty} { +\num{123.45(120)} \\ +\num{0.035(14)} \\ +\sisetup{uncertainty-mode = full} +\num{123.45(120)} \\ +\num{0.035(14)} \\ +\sisetup{uncertainty-mode = compact-marker} +\num{123.45(120)} \\ +\num{0.035(14)} \\ +%\sisetup{uncertainty-mode = separate} +\sisetup{ +output-open-uncertainty = [, +output-close-uncertainty = ], +uncertainty-separator = \, +}% \num{1.234(5)} \\ \num{1.234\pm 0.005} \\ -\num[separate-uncertainty = true]{1.234(5)} \\ -\num[separate-uncertainty = true]{1.234\pm 0.005} \\ -\sisetup{ - output-open-uncertainty = [, - output-close-uncertainty = ], - uncertainty-separator= {\,} -} -\num{1.234(5)}\\ -} +\num[uncertainty-mode = separate]{1.234(5)} \\ +\num[uncertainty-mode = separate]{1.234\pm 0.005} \\ \num{8.2(13)} \\ \num{8.2\pm1.3} \\ -\num[separate-uncertainty]{8.2(13)}\\ -\num[separate-uncertainty]{8.2\pm1.3} \\ - -\num{1.234(5) x \pi} \\ -\num[separate-uncertainty = true]{1.234(5) x \pi} \\ - +\num[uncertainty-mode = separate]{8.2(13)}\\ +\num[uncertainty-mode = separate]{8.2\pm1.3} \\ \num{1.2 +- 0.001}\\ -\num[separate-uncertainty]{1.2 +- 0.001}\\ +\num[uncertainty-mode = separate]{1.2 +- 0.001}\\ +} +\fbox{\parbox{4em}{% +\sisetup{uncertainty-mode = separate}% +\num{67890+-12345}\\ +\num[allow-uncertainty-breaks=false]{67890+-12345}% todo spacing +}} -\subsubsection{bracket-numbers, open-bracket, close-bracket} +\subsubsection{uncertainty-descriptors, uncertainty-descriptor-mode, uncertainty-descriptor-separator} % todo spacing, todo font { +\num{1.2(3)(4)} \\ +\sisetup{uncertainty-descriptors = {sys, stat}} +\num{1.2(3)(4)} \\ % default uncertainty-descriptor-mode = bracket-separator +\num[uncertainty-descriptor-mode = subscript]{1.2(3)(4)}\\ +\num[uncertainty-descriptor-mode = bracket]{1.2(3)(4)}\\ +\num[uncertainty-descriptor-mode = separator]{1.2(3)(4)}\\ +\num[uncertainty-mode=separate]{1.2(3)}\\ +\num[uncertainty-mode=separate]{1.2(3)(4)(5)}\\ +} +\num[uncertainty-mode=separate, uncertainty-descriptors={sys}]{1.2(3)}\\ +\num[uncertainty-mode=separate, uncertainty-descriptors={sys,stat,third}]{1.2(3)(4)} + +\subsubsection{simplify-uncertainty} +\num{10.56(2:2)} \\ +\num[simplify-uncertainty]{10.56(2:2)} + +\subsubsection{bracket-ambiguous-numbers} \num{1 e10} \\ -\num{2i e10} \\ -\num{1+2i e10} \\ -\num[bracket-numbers = false]{1+2i e10} \\ -\sisetup{ - open-bracket = \{, - close-bracket = \}, +\complexnum{2i e10} \\ +\complexnum{1+2i e10} \\ +\complexnum[bracket-ambiguous-numbers = false]{1+2i e10} \\ +{ +\sisetup{uncertainty-mode = separate} +\num{1.2(3)e4} \\ +\num[bracket-ambiguous-numbers = false]{1.2(3)e4} \\ } -\num{1+2i e10}\\ +{ +\sisetup{uncertainty-mode = separate, bracket-ambiguous-numbers = false}% +\num{1.234(5)e-4} %\\ +%\qty{1.234(5)e-4}{\metre} +% "This option only applies to pure numbers: when formatting quantities, +% the need for brackets also depends on the placement of units, so is controlled by separate-uncertainty-units." } \subsubsection{negative-color} \num{-15673} \\ \num[negative-color = red]{-15673} +also:\\ +\num[negative-color = red]{-0}\\ +\num[negative-color = red, retain-negative-zero]{-0}\\ +\num[color=green,negative-color=red]{-10}\\ +\num[negative-color=red,color=green]{-10} + +{\sisetup{negative-color=red} +\complexnum{1}\\ +\complexnum{-1}\\ +\complexnum{3i}\\ +\complexnum{-3i}\\ +\complexnum{1+3i}\\ +\complexnum{-1+3i}\\ +\complexnum{1-3i}\\ +\complexnum{-1-3i} +} + \subsubsection{bracket-negative-numbers} \num{-15673} \\ \num[bracket-negative-numbers]{-15673} \\ -%\SI{-10}{\metre} \\ -%\SI[bracket-negative-numbers]{-10}{\metre} +\qty{-10}{\metre} \\ +\qty[bracket-negative-numbers]{-10}{\metre} -\subsection{Multi-part Numbers} +{\sisetup{bracket-negative-numbers} +\num{<<-5}\\ +\num{-13(1)}\\ +\num{-13+-1}\\ +\num{-e10}\\ +\num{-2e10}\\ +\complexnum{1}\\ +\complexnum{-1}\\ +\complexnum{3i}\\ +\complexnum{-3i}\\ +\complexnum{1+3i}\\ +\complexnum{-1+3i}\\ +\complexnum{1-3i}\\ +\complexnum{-1-3i} +} -\subsubsection{input-product,input-quotient} -\num{1 x 2 x 3} \\ -\num{1e4 x 2(3) x 3/4} \\ -\num[input-product=*]{4 * 5 * 6} \\ -\num{ 1 / 2e4 } \\ -\num{ 1e2 / 3e4 }\\ +\subsubsection{tight-spacing} % todo spacing +\num{2e3} \\ +\num[tight-spacing = true]{2e3} + +\subsubsection{print-implicit-plus, print-[exponent\textbar mantissa]-implicit-plus} +a\\ +\num{345} \\ +\num[print-implicit-plus]{345} \\ +\num[print-mantissa-implicit-plus]{345} \\ +\num[print-exponent-implicit-plus]{345} \\ +b\\ +\num{1e2} \\ +\num[print-implicit-plus]{1e2} \\ +\num[print-mantissa-implicit-plus]{1e2} \\ +\num[print-exponent-implicit-plus]{1e2} \\ +c\\ +\num{1e+2} \\ +\num[print-implicit-plus]{1e+2} \\ +\num[print-mantissa-implicit-plus]{1e+2} \\ +\num[print-exponent-implicit-plus]{1e+2} \\ +d\\ +\num{-1e2} \\ +\num[print-implicit-plus]{-1e2} \\ +\num[print-mantissa-implicit-plus]{-1e2} \\ +\num[print-exponent-implicit-plus]{-1e2} \\ +e\\ +\num{1e-2} \\ +\num[print-implicit-plus]{1e-2} \\ +\num[print-mantissa-implicit-plus]{1e-2} \\ +\num[print-exponent-implicit-plus]{1e-2} + +\subsubsection{print-unity-mantissa, print-zero-[exponent\textbar integer]} +\num{1e4} \\ +\num[print-unity-mantissa = false]{1e4} \\ +\num{444e0} \\ +\num[print-zero-exponent = true]{444e0} \\ +\num{0.123} \\ +\num[print-zero-integer = false]{0.123} -\subsubsection{output-product, output-quotient} -\num[output-product = \cdot]{4.87 x 5.321 x 6.90545} \\ -\num[output-quotient = \text{ div }]{1 / 2}\\ +\num{e4}\\ +%\num[print-unity-mantissa]{e4}\\ +\num[print-unity-mantissa=false]{e4} -\subsubsection{quotient-mode} -\num{1 / 2e4} \\ -\num[quotient-mode = fraction]{1 / 2e4}\\ +\num[]{1e0}\\ +\num[print-unity-mantissa=false]{1e0}\\ % 1 should leak through as per documentation b/c print-zero-exponent=false +\num[print-zero-exponent=true]{1e0}\\ +\num[print-unity-mantissa=false, print-zero-exponent=true]{1e0} -\subsubsection{fraction-function} +\subsubsection{zero-decimal-as-symbol, zero-symbol} +\num{123.00} \\ { -\sisetup{quotient-mode= fraction} -\num{1 / 1}\\ -\num[fraction-function= \dfrac]{1 / 2}\\ -%\num[fraction-function= \sfrac]{1 / 3}\\ -\num[fraction-function= \tfrac]{1 / 4}\\ +\sisetup{zero-decimal-as-symbol} +\num{123.00} \\ +%\num{123.} \\ % v2 or v3 +\num{123} \\ +\num[zero-symbol = \text{[{---}]}]{123.00} } -\subsection{Lists and ranges of numbers} -\subsubsection{list-final-separator,list-pair-separator,list-separator} +\subsection{Lists, products and ranges} +\subsubsection{list-[final\textbar pair]-separator, list-separator} \numlist{0.1;0.2;0.3}\\ -\numlist[color=blue]{0.1;0.2;0.3}\\ \numlist[list-separator = {; }]{0.1;0.2;0.3}\\ \numlist[list-final-separator = {, }]{0.1;0.2;0.3} \\ \numlist[ -list-separator -= { and }, +list-separator = { and }, list-final-separator = { and finally } ]{0.1;0.2;0.3} \\ \numlist{0.1;0.2} \\ -\numlist[list-pair-separator = {, and }]{0.1;0.2}\\ +\numlist[list-pair-separator = {, and }]{0.1;0.2} \\ +\numlist[color=blue]{0.1;0.2;0.3} -\subsection{range-phrase} +\subsubsection{product-[mode\textbar phrase\textbar symbol]} +\numproduct{5 x 100 x 2} \\ +\numproduct[product-symbol = \ensuremath{\cdot}]{5 x 100 x 2} \\ +{ +\sisetup{product-mode = phrase}% +\numproduct{5 x 100 x 2}\\ +\numproduct[product-phrase = { BY }]{5 x 100 x 2} +} +\subsubsection{range-open-phrase, range-phrase} \numrange{5}{100} \\ \numrange[range-phrase = --]{5}{100}\\ -\numrange[color=blue,range-phrase = --]{5}{100}\\ +\numrange{10}{12} \\ +\numrange[range-open-phrase = {\text{from} }]{5}{100}\\ +\numrange[color=blue,range-phrase = --]{5}{100} + +\subsubsection{[list\textbar product\textbar range]-exponents} +\numlist{5e3;7e3;9e3;1e4} \\ +\numproduct{5e3 x 7e3 x 9e3 x 1e4} \\ +\numrange{5e3}{7e3} \\ +{ +\sisetup +{ +list-exponents = combine-bracket , +product-exponents = combine-bracket , +range-exponents = combine-bracket +} +\numlist{5e3;7e3;9e3;1e4} \\ +\numproduct{5e3 x 7e3 x 9e3 x 1e4} \\ +\numrange{5e3}{7e3} \\ +\numrange[range-open-phrase={\text{from }}]{5e3}{7e3} \\ +\sisetup +{ +list-exponents = combine , +product-exponents = combine , +range-exponents = combine +} +\numlist{5e3;7e3;9e3;1e4} \\ +\numproduct{5e3 x 7e3 x 9e3 x 1e4} \\ +\numrange{5e3}{7e3} +} + +\subsubsection{[list\textbar product\textbar range]-units} +\qtylist{2;4;6;8}{\tesla} \\ +\qtylist[list-units = bracket]{2;4;6;8}{\tesla} \\ +\qtylist[list-units = repeat]{2;4;6;8}{\tesla} \\ +\qtylist[list-units = single]{2;4;6;8}{\tesla} \\ +\qtyrange{2}{4}{\degreeCelsius} \\ +\qtyrange[range-units = bracket]{2}{4}{\degreeCelsius} \\ +\qtyrange[range-units = repeat]{2}{4}{\degreeCelsius} \\ +\qtyrange[range-units = single]{2}{4}{\degreeCelsius}\\ +\qtyproduct{2 x 3 x 4}{\metre} \\ +\qtyproduct[product-units = bracket]{2 x 3 x 4}{\metre}\\ +\qtyproduct[product-units = repeat]{2 x 3 x 4}{\metre}\\ +\qtyproduct[product-units = single]{2 x 3 x 4}{\metre}\\ +\qtyproduct[product-units = bracket-power]{2 x 3 x 4}{\metre}\\ +\qtyproduct[product-units = power]{2 x 3 x 4}{\metre} + +\subsubsection{[list\textbar product\textbar range]-[close\textbar open]-bracket} +{ +\sisetup{ +list-units = bracket , +list-open-bracket = [ , +list-close-bracket = ] +} +\qtylist{5e3;7e3;9e3;1e4}{\second} \\ +\sisetup{ +product-units = bracket , +product-open-bracket = \{ , +product-close-bracket = \} +} +\qtyproduct{5e3 x 7e3 x 9e3 x 1e4}{\metre} \\ +\sisetup{ +range-units = bracket , +range-open-bracket = \langle, +range-close-bracket = \rangle +} +\qtyrange{2}{4}{\degreeCelsius}\\ +\sisetup{ +list-units = bracket , +list-open-bracket = ( , +list-close-bracket = ) +} +\numlist{5e3;7e3;9e3;1e4} \\ +\sisetup{ +product-units = bracket , +product-open-bracket = ( , +product-close-bracket = ) +} +\numproduct{5e3 x 7e3 x 9e3 x 1e4} \\ +\sisetup{ +range-units = bracket , +range-open-bracket = ( , +range-close-bracket = ) +} +\qtyrange{2}{4}{\degreeCelsius} +} + +\subsubsection{[list\textbar product\textbar range]-independent-prefix} +{ +a\\ +\qtyrange{1e3}{1e9}{\watt}\\ +\qtylist{1e3;1e9}{\watt}\\ +\qtyproduct{1e3 x 1e9}{\watt}\\ +b\\ +\qtyrange[range-independent-prefix]{1e3}{1e9}{\watt}\\ +\qtylist[list-independent-prefix]{1e3;1e9}{\watt}\\ +$\qtyproduct[product-independent-prefix]{1e3 x 1e9}{\watt}$\\ +\sisetup{exponent-to-prefix}% +c\\ +\qtyrange{1000}{1e9}{\watt}\\ +\qtyrange{1e3}{1e9}{\watt}\\ +\qtylist{1000;1e9}{\watt}\\ +\qtylist{1e3;1e9}{\watt}\\ +\qtyproduct{1000 x 1e9}{\watt}\\ +\qtyproduct{1e3 x 1e9}{\watt}\\ +d\\ +\qtyrange[range-independent-prefix]{1e3}{1e9}{\watt}\\ +\qtylist[list-independent-prefix]{1e3;1e9}{\watt}\\ +$\qtyproduct[product-independent-prefix]{1e3 x 1e9}{\watt}$ +} + + +\subsubsection{prefix-mode = combine-exponent} +\qty{1700}{\g} \\ +\qty{1.7e3}{\g} \\ +{ +\sisetup{prefix-mode = combine-exponent}% +\qty{1700}{\g} \\ +\qty{1.7e3}{\g} \\ +} +{ +\sisetup{fixed-exponent = 3, exponent-mode = fixed}% +\qty{1700}{\g} \\ +\qty{1.7e3}{\g} +} + + +\subsection{Complex Numbers} +\subsubsection{complex-mode} +\complexnum{1 + i} \\ +\complexnum{1:45} \\ +\complexnum[complex-mode = cartesian]{1 + i} \\ +\complexnum[complex-mode = cartesian, round-mode = places]{1:45} \\ +\complexnum[complex-mode = polar]{1 + i} \\ +\complexnum[complex-mode = polar]{1:45} + +\subsubsection{input-complex-roots} +\complexnum{9.99 + 88.8i} \\ +\complexnum{9.99 + i88.8} + +\subsubsection{output-complex-root} % todo font +\complexnum{1+2i} \\ +\complexnum[output-complex-root = i]{1+2i} \\ +\complexnum[output-complex-root = \text{\ensuremath{i}}]{1+2i} \\ +\complexnum[output-complex-root = j]{1+2i} + +\subsubsection{complex-root-position} +\complexnum{67-0.9i} \\ +\complexnum[complex-root-position = before-number]{67-0.9i} \\ +\complexnum[complex-root-position = after-number]{67-0.9i} + +\subsubsection{complex-angle-unit, complex-symbol-angle, complex-symbol-degree} +\complexqty{1:1}{\ohm} \\ +\complexqty[complex-angle-unit = radians]{1:1}{\ohm} \\ +\complexqty[complex-symbol-degree = d]{1:1}{\ohm} +%\complexqty[complex-phase-command = \phase]{1:1}{\ohm} % needs steinmetz package + +\subsubsection{print-complex-unity} +\complexqty{1i}{\ohm} \\ +\complexqty[print-complex-unity]{1i}{\ohm}\\ +\complexqty[print-complex-unity]{i}{\ohm} + +\subsubsection{Other tests} +Real numbers as complex:\\ +\complexnum{1}\\ +\complexnum[print-complex-unity]{1}\\ +\complexnum[complex-mode=cartesian]{1:180}\\ +\complexnum[complex-mode=cartesian]{1:360}\\ +\complexnum[complex-mode=cartesian]{1:540}\\ +\complexnum[complex-mode=cartesian]{1:720}\\ +\complexnum[complex-mode=cartesian, complex-angle-unit=radians]{1:3.14159265359}\\ % Perl uses sci notation for these two +\complexnum[complex-mode=cartesian, complex-angle-unit=radians]{1:6.28318530718} % TeX doesn't + +\complexnum[complex-mode=polar, complex-angle-unit=radians]{i} \subsection{Angles} -\subsubsection{number-angle-product} +\subsubsection{angle-mode} \ang{2.67} \\ -\ang[number-angle-product = \,]{2.67} -\subsubsection{arc-separator} -\ang{6;7;6.5} \\ -\ang[arc-separator = \,]{6;7;6.5} -\subsubsection{add-arc-degree-zero,add-arc-minute-zero,add-arc-second-zero} +\ang{2;3;4} \\ +\ang[angle-mode = arc]{2.67} \\ +\ang[angle-mode = arc]{2;3;4} \\ +\ang[angle-mode = decimal]{2.67} \\ +\ang[angle-mode = decimal]{2;3;4} + +\subsubsection{angle-separator} +\ang{6;7;6.5} \\ % todo spacing +\ang[angle-separator = \,]{6;7;6.5} + +\subsubsection{fill-angle-[degrees\textbar minutes\textbar seconds]} \ang{-1;;} \\ \ang{;-2;} \\ \ang{;;-3} \\ { -\sisetup{add-arc-degree-zero} +\sisetup{fill-angle-degrees} \ang{-1;;} \\ \ang{;-2;} \\ \ang{;;-3} \\ } { -\sisetup{add-arc-minute-zero} +\sisetup{fill-angle-minutes} \ang{-1;;} \\ \ang{;-2;} \\ \ang{;;-3} \\ } { -\sisetup{add-arc-second-zero} +\sisetup{fill-angle-seconds} \ang{-1;;} \\ \ang{;-2;} \\ -\ang{;;-3}\\ +\ang{;;-3} \\ +} +\ang[fill-angle-minutes,fill-angle-seconds]{45.697}\\ +\ang[color=blue,fill-angle-minutes,fill-angle-seconds]{45.697} + +\subsubsection{angle-symbol-[degree\textbar minute\textbar second]} +{ +\ang{6;7;6.5} \\ +\sisetup{ +angle-symbol-degree = d , +angle-symbol-minute = m , +angle-symbol-second = s +} +\ang{6;7;6.5} } -\ang[add-arc-minute-zero,add-arc-second-zero]{45.697}\\ -\ang[color=blue,add-arc-minute-zero,add-arc-second-zero]{45.697}\\ \subsubsection{angle-symbol-over-decimal} \ang{45.697} \\ @@ -430,559 +1458,218 @@ \subsubsection{angle-symbol-over-decimal} % \ang{+10;;}\\ % \ang{-0;1;}\\ +\stepcounter{subsection} -\section{Units} -\def\showunit#1{#1 & \texttt{\Backslash#1} & \si{\csname#1\endcsname}} -\begin{table} -\caption{SI base units} -\centering -\begin{tabular}{lll}\hline\hline -Unit & Macro & Symbol \\\hline -\showunit{ampere}\\ -\showunit{candela}\\ -\showunit{kelvin}\\ -\showunit{kilogram}\\ -\showunit{metre}\\ -\showunit{mole}\\ -\showunit{second}\\ -\end{tabular} -\end{table} - -\begin{table} -\caption{Coherent derived units} -\centering -\begin{tabular}{llllll}\hline\hline -Unit & Macro & Symbol & -Unit & Macro & Symbol \\\hline -\showunit{becquerel} & \showunit{newton} \\ -\showunit{degreeCelsius} & \showunit{ohm} \\ -\showunit{coulomb} & \showunit{pascal} \\ -\showunit{farad} & \showunit{radian} \\ -\showunit{gray} & \showunit{siemens} \\ -\showunit{hertz} & \showunit{sievert} \\ -\showunit{henry} & \showunit{steradian} \\ -\showunit{joule} & \showunit{tesla} \\ -\showunit{katal} & \showunit{volt} \\ -\showunit{lumen} & \showunit{watt} \\ -\showunit{lux} & \showunit{weber} \\ -\end{tabular} -\end{table} - -\begin{table} -\caption{Non-SI units} -\centering -\begin{tabular}{lll}\hline\hline -Unit & Macro & Symbol \\\hline -\showunit{day}\\ -\showunit{degree}\\ -\showunit{hectare}\\ -\showunit{hour} \\ -\showunit{litre}\\ -\showunit{liter}\\ -\showunit{arcminute}\\ -\showunit{minute}\\ -\showunit{arcsecond}\\ -\showunit{tonne}\\ -\end{tabular} -\end{table} - -\begin{table} -\caption{Expermental Non-SI units} -\centering -\begin{tabular}{lll}\hline\hline -Unit & Macro & Symbol \\\hline -\showunit{astronomicalunit}\\ -\showunit{atomicmassunit}\\ -\showunit{bohr}\\ -\showunit{clight}\\ -\showunit{dalton}\\ -\showunit{electronmass}\\ -\showunit{electronvolt}\\ -\showunit{elementarycharge}\\ -\showunit{hartree}\\ -\showunit{planckbar}\\ -\end{tabular} -\end{table} - -\begin{table} -\caption{Other non-SI units} -\centering -\begin{tabular}{lll}\hline\hline -Unit & Macro & Symbol \\\hline -\showunit{angstrom}\\ -\showunit{bar}\\ -\showunit{barn}\\ -\showunit{bel}\\ -\showunit{decibel}\\ -\showunit{knot}\\ -\showunit{mmHg}\\ -\showunit{nauticalmile}\\ -\showunit{neper}\\ -\end{tabular} -\end{table} - -\def\showprefix#1{#1 & \texttt{\Backslash#1} & \si{\csname#1\endcsname} & \si[prefixes-as-symbols=false]{\csname#1\endcsname}} -\begin{table} -\caption{Other non-SI units} -\centering -\begin{tabular}{llllllll}\hline\hline -Unit & Macro & Symbol & Power & -Unit & Macro & Symbol & Power \\\hline -\showprefix{yocto} & \showprefix{deca}\\ -\showprefix{zepto} & \showprefix{hecto}\\ -\showprefix{atto} & \showprefix{kilo}\\ -\showprefix{femto} & \showprefix{mega}\\ -\showprefix{pico} & \showprefix{giga}\\ -\showprefix{nano} & \showprefix{tera}\\ -\showprefix{micro} & \showprefix{peta}\\ -\showprefix{milli} & \showprefix{exa}\\ -\showprefix{centi} & \showprefix{zetta}\\ -\showprefix{deci} & \showprefix{yotta}\\ -\end{tabular} -\end{table} - - -\begin{table} -\caption{Abbreviated units} -\centering -\begin{tabular}{lll}\hline\hline -Unit & Macro & Symbol \\\hline -\showunit{fg}\\ -\showunit{pg}\\ -\showunit{ng}\\ -\showunit{ug}\\ -\showunit{mg}\\ -\showunit{g}\\ -\showunit{kg}\\ -\showunit{amu}\\\hline -\showunit{pm}\\ -\showunit{nm}\\ -\showunit{um}\\ -\showunit{mm}\\ -\showunit{cm}\\ -\showunit{dm}\\ -\showunit{m}\\ -\showunit{km}\\\hline -\showunit{as}\\ -\showunit{fs}\\ -\showunit{ps}\\ -\showunit{ns}\\ -\showunit{us}\\ -\showunit{ms}\\ -\showunit{s}\\\hline -\showunit{fmol}\\ -\showunit{pmol}\\ -\showunit{nmol}\\ -\showunit{umol}\\ -\showunit{mmol}\\ -\showunit{mol}\\ -\showunit{kmol}\\\hline -\showunit{pA}\\ -\showunit{nA}\\ -\showunit{uA}\\ -\showunit{mA}\\ -\showunit{A}\\ -\showunit{kA}\\\hline -\showunit{ul}\\ -\showunit{ml}\\ -\showunit{l}\\ -\showunit{hl}\\ -\showunit{uL}\\ -\showunit{mL}\\ -\showunit{L}\\ -\showunit{hL}\\\hline -\showunit{mHz}\\ -\showunit{Hz}\\ -\showunit{kHz}\\ -\showunit{MHz}\\ -\showunit{GHz}\\ -\showunit{THz}\\\hline -\showunit{mN}\\ -\showunit{N}\\ -\showunit{kN}\\ -\showunit{MN}\\\hline -\showunit{Pa}\\ -\showunit{kPa}\\ -\showunit{MPa}\\ -\showunit{GPa}\\\hline -\showunit{mohm}\\ -\showunit{kohm}\\ -\showunit{Mohm}\\\hline -\showunit{pV}\\ -\showunit{nV}\\ -\showunit{uV}\\ -\showunit{mV}\\ -\showunit{V}\\ -\showunit{kV}\\\hline -\showunit{W}\\ -\showunit{uW}\\ -\showunit{mW}\\ -\showunit{kW}\\ -\showunit{MW}\\ -\showunit{GW}\\\hline -\showunit{J}\\ -\showunit{kJ}\\\hline -\showunit{eV}\\ -\showunit{meV}\\ -\showunit{keV}\\ -\showunit{MeV}\\ -\showunit{GeV}\\ -\showunit{TeV}\\\hline -\showunit{kWh}\\\hline -\showunit{F}\\ -\showunit{fF}\\ -\showunit{pF}\\\hline -\showunit{K}\\\hline -\showunit{dB}\\\hline -\end{tabular} -\end{table} - -\begin{table} -\caption{Binary prefixes} -\centering -\begin{tabular}{llllllll}\hline\hline -Unit & Macro & Symbol & Power \\\hline -\showprefix{kibi} \\ -\showprefix{mebi} \\ -\showprefix{gibi} \\ -\showprefix{tebi} \\ -\showprefix{pebi} \\ -\showprefix{exbi} \\ -\showprefix{zebi} \\ -\showprefix{yobi} \\ -\end{tabular} -\end{table} +\subsection{Using Units} +\subsubsection{inter-unit-product} +\unit{\farad\squared\lumen\candela} \\ +\unit[inter-unit-product = \ensuremath{{}\cdot{}}]{\farad\squared\lumen\candela}\\ +\unit[color=blue,inter-unit-product = \ensuremath{{}\cdot{}}]{\farad\squared\lumen\candela} -%\subsection{Creating Units} -%\subsection{Loading additional units} +\subsubsection{per-mode, [display\textbar inline]-per-mode, per-symbol, fraction-command, bracket-unit-denominator} +\unit{\joule\per\mole\per\kelvin} \\ +\unit{\metre\per\second\squared} \\ +\unit[per-mode=fraction]{\joule\per\mole\per\kelvin} \\ +\unit[per-mode=fraction]{\joule\raiseto{-1}\mole\per\kelvin} \\ +\unit[per-mode=fraction]{\metre\per\second\squared}\\ +\unit{\ampere\per\mole\second} \\ +\unit[per-mode = power-positive-first]{\ampere\per\mole\second} -\subsection{Using units} -% Note that \kilogram is defined as \kilo\gram, and acts sorta like a macro -\si{\kilogram} -\si{\kilo\gram} -% Not allowed. -%\si{\kilo\kilogram} -%\si{\kilo\kilo\gram} -{ -% and note that regular macros ARE expanded! -\def\killermeater{\kilo\meter} -\si{\killermeater} -} { -% BUT, it prefers its OWN definitions! -\def\gram{Grr} -\si{\kilo\gram} +\sisetup{per-mode = symbol}% +\unit{\joule\per\mole\per\kelvin} \\ +\unit{\metre\per\second\squared} \\ +\unit[per-symbol = \ \text{div}\ ]{\joule\per\mole\per\kelvin} \\ +\unit[bracket-unit-denominator = false]{\joule\per\mole\per\kelvin}\\ } - -% However, it's happy with various indirect definitions. -% Ie. units, prefixes (at least) act like regular macros within \si. -\si{\abbra}\\ -\si{\abbrb}\\ -\si{\abbrc}\\ -\si{\abbrd}\\ -\si{\abbre}\\ - -\si{\mabbra}\\ -\si{\mabbrb}\\ - -\si{\killer\meter}\\ - -% Where can highlight go? -\si{\highlight{red}\kilo\gram\metre\per\second} \\ -\si{\kilo\highlight{red}\gram\metre\per\second} \\ -\si{\kilo\gram\highlight{red}\metre\per\second} \\ -\si{\kilo\gram\metre\highlight{red}\per\second} \\ -\si{\kilo\gram\metre\per\highlight{red}\second} \\ - -\si{\cancel\kilo\gram\metre\per\second} \\ -\si{\kilo\cancel\gram\metre\per\second} \\ -\si{\kilo\gram\cancel\metre\per\second} \\ -\si{\kilo\gram\metre\cancel\per\second} \\ -\si{\kilo\gram\metre\per\cancel\second} \\ - -\subsubsection{forbid-literal-units, inter-unit-product} -\si{\farad\squared\lumen\candela} \\ -\si[inter-unit-product = \ensuremath{{}\cdot{}}]{\farad\squared\lumen\candela}\\ -\si[color=blue,inter-unit-product = \ensuremath{{}\cdot{}}]{\farad\squared\lumen\candela}\\ -\subsubsection{per-mode, per-symbol, bracket-unit-denominator} -\si{\joule\per\mole\per\kelvin} \\ -\si{\metre\per\second\squared} \\ -\si[per-mode=fraction]{\joule\per\mole\per\kelvin} \\ -\si[per-mode=fraction]{\joule\raiseto{-1}\mole\per\kelvin} \\ -\si[per-mode=fraction]{\metre\per\second\squared}\\ -\si{\ampere\per\mole\second} \\ -\si[per-mode = reciprocal-positive-first]{\ampere\per\mole\second} +\unit[per-mode=repeated-symbol]{\joule\per\mole\per\kelvin} { -\sisetup{per-mode = symbol}% -\si{\joule\per\mole\per\kelvin} \\ -\si{\metre\per\second\squared} \\ -\si[per-symbol = \text{~div~}]{\joule\per\mole\per\kelvin} \\ -\si[bracket-unit-denominator = false]{\joule\per\mole\per\kelvin}\\ +\sisetup{per-mode = single-symbol} +\qty{10}{\per\metre} \\ +\qty{20}{\metre\per\second} \\ +\qty{30}{\joule\per\mole\per\kelvin} } -\si[per-mode=repeated-symbol]{\joule\per\mole\per\kelvin}\\ + { -\sisetup{per-mode = symbol-or-fraction}% -\( \si{\joule\per\mole\per\kelvin} \) -\[ \si{\joule\per\mole\per\kelvin} \] -\si{\joule\per\mole\per\kelvin} \\ +\sisetup{ +display-per-mode = fraction , +inline-per-mode = symbol +}% +\( \unit{\joule\per\mole\per\kelvin} \) +\[ \unit{\joule\per\mole\per\kelvin} \] +\unit{\joule\per\mole\per\kelvin} \\ \( \displaystyle -\si{\joule\per\mole\per\kelvin} +\unit{\joule\per\mole\per\kelvin} \) \[ \textstyle -\si{\joule\per\mole\per\kelvin} +\unit{\joule\per\mole\per\kelvin} \] \[ \textstyle -\si[color=blue]{\joule\per\mole\per\kelvin} +\unit[color=blue]{\joule\per\mole\per\kelvin} \] } -\subsubsection{sticky-per} -\si{\pascal\per\gray\henry} \\ -\si[sticky-per]{\pascal\per\gray\henry}\\ - -\subsubsection{power-font} -\si{\metre\per\second\squared} \\ -\si[power-font = unit]{\metre\per\second\squared}\\ - -\subsubsection{literal-superscript-as-power} -\si{m.s^{2}} \\ -\si[literal-superscript-as-power = false]{m.s^{2}}\\ - -\subsubsection{qualifier-mode, qualifier-phrase} -\si{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ -\si[qualifier-mode = brackets] -{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ -\si[qualifier-mode = subscript] -{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ -\si[qualifier-mode = space] -{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ -\si[qualifier-mode = text] -{\deci\bel\isotropic}\\ - -\si[qualifier-mode = phrase] -{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ -\si[qualifier-mode = phrase, qualifier-phrase = { by }] -{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ - -\subsubsection{prefixes-as-symbols} -\si{\milli\litre\per\mole\deci\ampere} \\ -%%\SI{10}{\kilo\gram\squared\deci\second} \\ -\si[prefixes-as-symbols=false]{\milli\litre\per\mole\deci\ampere}\\ -\si[prefixes-as-symbols=false]{\kilo\gram\squared\deci\second}\\ -\si{\mega\gram\squared\deci\second}\\ -\si[prefixes-as-symbols=false]{\mega\gram\squared\deci\second}\\ -\si{\micro\gram\squared\deci\second}\\ -\si[prefixes-as-symbols=false]{\micro\gram\squared\deci\second}\\ -\si{\per\mega\gram\squared\deci\second}\\ -\si[prefixes-as-symbols=false]{\per\mega\gram\squared\deci\second}\\ -\si{\per\micro\gram\squared\deci\second}\\ -\si[prefixes-as-symbols=false]{\per\micro\gram\squared\deci\second}\\ -%%\SI[prefixes-as-symbols=false]{10}{\kilo\gram\squared\deci\second}\\ - -\subsubsection{parse-units} -%%\SI{300}{\MHz} \\ -%%\SI[parse-units = false]{300}{\MHz}\\ - -\subsection{Numbers with units} -\subsubsection{allow-number-unit-breaks} -\subsubsection{number-unit-product} -\SI{2.67}{\farad} \\ -\SI[number-unit-product = \ ]{2.67}{\farad} \\ -\SI[number-unit-product = ]{2.67}{\farad}\\ -\SI[number-unit-product = \,]{2.67}{\farad}\\ -\SI[number-unit-product = \;]{2.67}{\farad}\\ -\SI[number-unit-product = $\times$]{2.67}{\farad}\\ -\SI[color=blue,number-unit-product = $\times$]{2.67}{\farad}\\ -\subsubsection{multi-part-units} -{ -\sisetup{separate-uncertainty}% -\SI{12.3(4)}{\kilo\gram} \\ -\SI[multi-part-units = brackets]{12.3(4)}{\kilo\gram} \\ -\SI[multi-part-units = repeat]{12.3(4)}{\kilo\gram}\\ -\SI[multi-part-units = single]{12.3(4)}{\kilo\gram}\\ -} - -{ -\sisetup{separate-uncertainty,bracket-numbers = false}% -\num{1.234(5)e-4} \\ -\SI{1.234(5)e-4}{\metre}\\ -} -\subsubsection{product-units} -\SI{2 x 3 x 4}{\metre} \\ -\SI[product-units = brackets]{2 x 3 x 4}{\metre}\\ -\SI[product-units = brackets-power]{2 x 3 x 4}{\metre}\\ -\SI[product-units = power]{2 x 3 x 4}{\metre}\\ -\SI[product-units = repeat]{2 x 3 x 4}{\metre}\\ -\SI[product-units = single]{2 x 3 x 4}{\metre}\\ - -\subsubsection{list-units,range-units} -\SIlist{2;4;6;8}{\tesla} \\ -\SIlist[list-units = brackets]{2;4;6;8}{\tesla} \\ -\SIlist[list-units = repeat]{2;4;6;8}{\tesla} \\ -\SIlist[list-units = single]{2;4;6;8}{\tesla} \\ -\SIrange{2}{4}{\degreeCelsius} \\ -\SIrange[range-units = brackets]{2}{4}{\degreeCelsius} \\ -\SIrange[range-units = repeat]{2}{4}{\degreeCelsius} \\ -\SIrange[range-units = single]{2}{4}{\degreeCelsius}\\ - -\subsubsection{exponent-to-prefix} -\SI{1700}{\g} \\ -\SI{1.7e3}{\g} \\ -{ -\sisetup{exponent-to-prefix}% -\SI{1700}{\g} \\ -\SI{1.7e3}{\g} \\ -} -{ -\sisetup{fixed-exponent = 3, scientific-notation = fixed}% -\SI{1700}{\g} \\ -\SI{1.7e3}{\g}\\ -} - - -\section{Tabular material} -% \begin{tabular}{S} -% 2.3456 \\ -% \end{tabular} -% \end{document} - - -\begin{table}[H] -\caption{Standard behaviour of the \texttt{S} column type.} -\label{tab:S:standard} -\centering -\begin{tabular}{S} -\toprule -{Some Values} \\ -\midrule -2.3456 \\ -34.2345 \\ --6.7835 \\ -90.473 \\ -5642.5 \\ -1.2e3 \\ -e4 \\ -\bottomrule -\end{tabular} -\end{table} +\newcommand{\myfraction}[2]{#1~\text{over }#2} +Other tests:\\ +\unit[per-mode=single-symbol]{\meter\per\second\liter}\\ +\unit[per-mode=fraction, fraction-command=\myfraction]{\joule\per\mole\per\kelvin} +\subsubsection{per-symbol-script-correction} +{ +\sisetup{per-mode = symbol}% +\unit{\cm\cubed\per\gram} \\ +\unit[per-symbol-script-correction = ]{\cm\cubed\per\gram} % todo spacing +} -%\end{document} +\subsubsection{sticky-per} +\unit{\pascal\per\gray\henry} \\ +\unit[sticky-per]{\pascal\per\gray\henry} + +\subsubsection{qualifier-[mode\textbar phrase]} +\unit{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ +\unit[qualifier-mode = bracket]{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ +\unit[qualifier-mode = subscript]{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ +\unit[qualifier-mode = phrase, qualifier-phrase=\ ]{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ +\unit[qualifier-mode = combine]{\deci\bel\isotropic}\\ +\unit{\kilogram\of{pol}\squared\per\mole\of{cat}\per\hour} \\ +\unit[qualifier-mode = bracket]{\kilogram\of{pol}\squared\per\mole\of{cat}\per\hour} \\ +\unit[qualifier-mode = combine]{\deci\bel\of{i}} \\ +{ +\sisetup{qualifier-mode = phrase, qualifier-phrase = \ }% +\unit{\kilogram\of{pol}\squared\per\mole\of{cat}\per\hour} \\ +\sisetup{qualifier-phrase = \ \mbox{of}\ }% +\unit{\kilogram\of{pol}\squared\per\mole\of{cat}\per\hour} +} +%\unit[qualifier-mode = phrase]{\kilogram\polymer\squared\per\mole\catalyst\per\hour} \\ +\unit[qualifier-mode = phrase, qualifier-phrase = { by }]{\kilogram\polymer\squared\per\mole\catalyst\per\hour} +% keep an eye on siunitx#854 +\unit[qualifier-mode = bracket]{\kilogram\polymer\squared} \\ % v2 invalid; v3 kg(pol)^2 +\unit[qualifier-mode = brackets]{\kilogram\polymer\squared} \\ % kg(pol)^2 +\unit[qualifier-mode = phrase, qualifier-phrase = {\;}]{\kilogram\polymer\squared} \\ % v2 (kg pol)^2; v3 kg pol^2 +\unit[qualifier-mode = space]{\kilogram\polymer\squared} \\ % v2 (kg pol)^2; v3 kg pol^2 +\unit[qualifier-mode = combine]{\kilogram\polymer\squared} \\ % v2 invalid; v3 kgpol^2 +\unit[qualifier-mode = text]{\kilogram\polymer\squared} % kgpol^2 +\subsubsection{power-half-as-sqrt} +\unit{\Hz\tothe{0.5}} \\ +\unit[power-half-as-sqrt]{\Hz\tothe{0.5}} -\begin{table}[H] -\caption{Detection of surrounding material in an \texttt{S} column.} -\label{tab:S:extras} -\centering -\begin{tabular}{S[color=orange]} -\toprule -{Some Values} \\ -\midrule -12.34 \\ -\color{purple} 975,31 \\ -44.268 \textsuperscript{\emph{a}} \\ -\bottomrule -\end{tabular} -\end{table} +\subsubsection{parse-units} +\qty{300}{\MHz} \\ +\qty[parse-units = false]{300}{\MHz} \\ +\unit{\meter\per\second} \\ +\unit[parse-units=false]{\meter\per\second} +% Setting parse-units=false speeds things up by making many default assumptions. +% It's not clear which assumptions we miss. +% per-mode is the only one I know of. +% see siunitx#840 + +\subsubsection{forbid-literal-units} +\unit{m/s}\\ +%\unit[forbid-literal-units]{m/s}\\ % raise an error +\unit[forbid-literal-units]{\meter\per\second} + +\subsubsection{unit-font-command} % todo font +\unit{\lumen} \\ +\unit[unit-font-command = \mathit]{\lumen} + +\subsection{Quantities} +\subsubsection{allow-quantity-breaks} +\begin{minipage}{3cm} +% Gives an underfull hbox +X\hspace{2.4cm}\qty{10}{\metre} \\ +X\hspace{2.1cm}\qty{10}{\metre} \\ +\sisetup{allow-quantity-breaks} +X\hspace{2.4cm}\qty{10}{\metre} \\ % disagrees with texdoc? % todo spacing +X\hspace{2.1cm}\qty{10}{\metre} % todo spacing +\end{minipage} + +\subsubsection{quantity-product} % todo spacing +\qty{2.67}{\farad} \\ +\qty[quantity-product = \ ]{2.67}{\farad} \\ +\qty[quantity-product = ]{2.67}{\farad}\\ +\qty[quantity-product = \,]{2.67}{\farad}\\ +\qty[quantity-product = \;]{2.67}{\farad}\\ +\qty[quantity-product = $\times$]{2.67}{\farad}\\ +\qty[color=blue,quantity-product = $\times$]{2.67}{\farad}\\ +also\\ +\qty[quantity-product = $\times$, separate-uncertainty]{3.7+-4.5}{\farad} + + +\subsubsection{prefix-mode, extract-mass-in-kilograms} +\qty{1e3}{\metre\second} \\ +\qty[prefix-mode = combine-exponent]{1e3}{\metre\second} \\ +\qty{10}{\kilo\gram\squared\deci\second} \\ +\qty[prefix-mode = extract-exponent]{10}{\kilo\gram\squared\deci\second}\\ +\qty[prefix-mode = extract-exponent]{7.5}{\gram} \\ +{ +\sisetup{extract-mass-in-kilograms = false} +\qty{10}{\kilo\gram\squared\deci\second} \\ +\qty[prefix-mode = extract-exponent]{10}{\kilo\gram\squared\deci\second} \\ +\qty[prefix-mode = extract-exponent]{7.5}{\gram} +} -\begin{table}[H] -\caption{Controlling complex alignment with the tablenum macro.} -\label{tab:tablenum} -\centering -\begin{tabular}{lr} -\toprule -Heading & Heading \\ -\midrule -Info & More info \\ -Info & More info \\ -\multicolumn{2}{c}{\tablenum[table-format = 4.4]{12,34}} \\ -\multicolumn{2}{c}{\tablenum[table-format = 4.4]{333.5567}} \\ -\multicolumn{2}{c}{\tablenum[table-format = 4.4]{4563.21}} \\ -\bottomrule -\end{tabular} -\hfil -\begin{tabular}{lr} -\toprule -Heading & Heading \\ -\midrule -\multirow{2}*{\tablenum{88,999}} & aaa \\ -& bbb \\ -\multirow{2}*{\tablenum{33,435}} & ccc \\ -& ddd \\ -\bottomrule -\end{tabular} -\end{table} +\unit{\milli\litre\per\mole\deci\ampere} \\ +%%\qty{10}{\kilo\gram\squared\deci\second} \\ +\unit[prefix-mode = extract-exponent]{\milli\litre\per\mole\deci\ampere}\\ +\unit[prefix-mode = extract-exponent]{\kilo\gram\squared\deci\second}\\ +\unit{\mega\gram\squared\deci\second}\\ +\unit[prefix-mode = extract-exponent]{\mega\gram\squared\deci\second}\\ +\unit{\micro\gram\squared\deci\second}\\ +\unit[prefix-mode = extract-exponent]{\micro\gram\squared\deci\second}\\ +\unit{\per\mega\gram\squared\deci\second}\\ +\unit[prefix-mode = extract-exponent]{\per\mega\gram\squared\deci\second}\\ +\unit{\per\micro\gram\squared\deci\second}\\ +\unit[prefix-mode = extract-exponent]{\per\micro\gram\squared\deci\second} +%%\qty[prefix-mode = extract-exponent]{10}{\kilo\gram\squared\deci\second}\\ + +\subsubsection{separate-uncertainty-units} +{ +\sisetup{uncertainty-mode = separate}% +\qty{12.3(4)}{\kilo\gram} \\ +\qty[separate-uncertainty-units = bracket]{12.3(4)}{\kilo\gram} \\ +\qty[separate-uncertainty-units = repeat]{12.3(4)}{\kilo\gram}\\ +\qty[separate-uncertainty-units = single]{12.3(4)}{\kilo\gram} +} -\begin{table}[H] -\centering -\caption{Units in tables.} -\label{tab:s:demo} -\begin{tabular}{s} -\toprule -\multicolumn{1}{c}{Unit} \\ -\midrule -\metre\squared\per\second \\ -\pascal \\ -m.s^{-1} \\ -\bottomrule -\end{tabular} -\end{table} - -\begin{table}[H] -\centering -\caption{The \texttt{s} column processes everything.} -\label{tab:s:processing} -\sisetup{color = orange} -\begin{tabular}{ss} -\toprule -{Unit} -& \multicolumn{1}{c}{Unit}\\ -\midrule -{\si{m^3}} & \multicolumn{1}{c}{\si{m^3}} \\ -\kilogram -& \kilogram \\ -\bottomrule -\end{tabular} -\end{table} - -\subsubsection{table-parse-only} -\begin{table}[H] -\centering -\caption{Parsing without aligning in an \texttt{S} column.} -\label{tab:S:parse} -\begin{tabular}{SS[table-parse-only]} +\subsection{Tabular Material} + +\subsubsection{table-alignment-mode} + +Parsing without aligning in an \texttt{S} column +\begin{center} +\begin{tabular} +{@{}S +S[table-alignment-mode = none] +@{}} \toprule -{Decimal-centred} & -{Simple centring} \\ +{Decimal-centered} & +{Simple centering} \\ \midrule 12.345 & 12.345 \\ -6,78 & 6,78 \\ +6,78 & 6,78 \\ -88.8(9) & -88.8(9) \\ -4.5e3 & 4.5e3 \\ +4.5e3 & 4.5e3 \\ \bottomrule \end{tabular} -\end{table} +\end{center} \subsubsection{table-number-alignment} -\begin{table}[H] -\caption{Aligning the \texttt{S} column.} -\label{tab:S:align} -\centering -\sisetup{ -table-figures-integer = 2, -table-figures-decimal = 4 -} -\begin{tabular}{ -S + +Aligning the \texttt{S} column +\begin{center} +\sisetup{table-format = 2.4, table-alignment-mode = format} +\begin{tabular}{@{} +S[table-alignment-mode = marker] S[table-number-alignment = center] S[table-number-alignment = left] S[table-number-alignment = right] -} +@{}} \toprule {Some Values} & {Some Values} & {Some Values} & {Some Values} \\ \midrule @@ -992,130 +1679,48 @@ \subsubsection{table-number-alignment} 90.473 & 90.473 & 90.473 & 90.473\\ \bottomrule \end{tabular} -\end{table} +\end{center} -\subsubsection{table-figures-decimal, table-figures-exponent,table-figures-integer,table-figures- -uncertainty} - -\begin{table}[H] -\caption{Reserving space in \texttt{S} columns.} -\label{tab:S:space} -\sisetup{ -table-number-alignment = center, -table-figures-integer = 2 -} -\centering -\begin{tabular}{ -S -S[table-number-alignment = right] -S[table-figures-uncertainty = 1] -S[separate-uncertainty, table-figures-uncertainty = 1] -S[table-sign-mantissa] -S[table-figures-exponent = 1] -} -\toprule -{Values} -& {Values} -& {Values} -& {Values} -& {Values} -& {Values} \\ -\midrule -2.3 & 2.3 & 2.3(5) & 2.3(5) & 2.3 & 2.3e8\\ -34.23 & 34.23 & 34.23(4) & 34.23(4) & 34.23 & 34.23\\ -56.78 & 56.78 & 56.78(3) & 56.78(3) & -56.78 & 56.78e3\\ -3,76 & 3,76 & 3,76(2) & 3.76(2) & +-3.76 & e6\\ -\bottomrule -\end{tabular} -\end{table} +\subsubsection{table-format} -\subsubsection{table-comparator} -\begin{table}[H] -\caption{Reserving space for comparators in \texttt{S} columns.} -\label{tab:S:comparators} +Reserving space in \texttt{S} columns +\begin{center} \sisetup{ +table-alignment-mode = format, table-number-alignment = center, -table-figures-integer = 2, -table-figures-decimal = 2, -table-figures-exponent = 2, } -\centering -\begin{tabular}{ -S -S[table-comparator = true]} -\toprule -{Values} -& {Values} \\ -\midrule -2 .3 & < 2.3e8\\ -34.23 & = 34.23 \\ -56.78 & >= 56.78e3\\ -3,76 & \gg e6 \\ -\bottomrule -\end{tabular} -\end{table} - -\subsubsection{table-format} -\begin{table}[H] -\caption{Using the \texttt{table-format} option.} -\label{tab:S:format} -\centering -\begin{tabular}{ -S +\begin{tabular}{@{} S[table-format = 2.2] +S[table-format = 2.2, table-number-alignment = right] S[table-format = 2.2(1)] +S[table-format = 2.2(1), uncertainty-mode = separate] S[table-format = +2.2] S[table-format = 2.2e1] -} +@{}} \toprule {Values} & {Values} & {Values} & {Values} +& {Values} & {Values} \\ \midrule -2.3 & 2.3 & 2.3(5) & 2.3 & 2.3e8 \\ -34.23 & 34.23 & 34.23(4) & 34.23 & 34.23 \\ -56.78 & 56.78 & 56.78(3) & -56.78 & 56.78e3 \\ -3,76 & 3,76 & 3.76(2) & +-3.76 & e6 \\ +2.3 & 2.3 & 2.3(5) & 2.3(5) & 2.3 & 2.3e8 \\ +34.23 & 34.23 & 34.23(4) & 34.23(4) & 34.23 & 34.23 \\ +56.78 & 56.78 & 56.78(3) & 56.78(3) & -56.78 & 56.78e3 \\ +3,76 & 3,76 & 3,76(2) & 3.76(2) & +-3.76 & e6 \\ \bottomrule \end{tabular} -\end{table} +\end{center} +\subsubsection{table-model-setup} -\subsubsection{table-space-text-pre, table-space-text-post} -\begin{table}[H] -\caption{Text before and after numbers.} -\label{tab:S:ends} -\centering -\sisetup{ -table-number-alignment = center, -table-figures-integer = 2, -table-figures-decimal = 4, -table-space-text-pre -= now~, -table-space-text-post = -\textsuperscript{\emph{a}} -} -\begin{tabular}{S} -\toprule -{Values} \\ -\midrule -2.3456 \\ -34.2345 \textsuperscript{\emph{a}}\\ -56.7835 \\ -now~ 90.473 \\ -\bottomrule -\end{tabular} -\end{table} - -\subsubsection{table-align-comparator, table-align-exponent, table-align-uncertainty} -\begin{table}[H] -\centering -\caption{The \texttt{table-align-exponent} option} -\label{tab:align:exp} -\sisetup{table-format = 1.3e2, table-number-alignment = center} -\begin{tabular}{SS[table-align-exponent = false]} +\subsubsection{table-align-[comparator\textbar exponent\textbar uncertainty]} + +The \texttt{table-align-exponent} option +\begin{center} +\sisetup{table-format = 1.3e2} +\begin{tabular}{@{}SS[table-align-exponent = false]@{}} \toprule {Header} & {Header} \\ \midrule @@ -1123,17 +1728,15 @@ \subsubsection{table-align-comparator, table-align-exponent, table-align-uncerta 1.234e56 & 1.234e56 \\ \bottomrule \end{tabular} -\end{table} +\end{center} -\begin{table}[H] -\centering -\caption{The \texttt{table-align-uncertainty} option} -\label{tab:align:uncert} +The \texttt{table-align-uncertainty} option +\begin{center} \sisetup{ -separate-uncertainty, +uncertainty-mode = separate, table-format = 1.3(1), } -\begin{tabular}{SS[table-align-uncertainty = false]} +\begin{tabular}{@{}SS[table-align-uncertainty = false]@{}} \toprule {Header} & {Header} \\ \midrule @@ -1141,14 +1744,12 @@ \subsubsection{table-align-comparator, table-align-exponent, table-align-uncerta 1.234(5) & 1.234(5) \\ \bottomrule \end{tabular} -\end{table} +\end{center} -\begin{table}[H] -\centering -\caption{The \texttt{table-align-comparator} option} -\label{tab:align:comp} +The \texttt{table-align-comparator} option +\begin{center} \sisetup{table-format = >2.2} -\begin{tabular}{SS[table-align-comparator = false]} +\begin{tabular}{@{}SS[table-align-comparator = false]@{}} \toprule {Header} & {Header} \\ \midrule @@ -1156,103 +1757,75 @@ \subsubsection{table-align-comparator, table-align-exponent, table-align-uncerta < 12.34 & < 12.34 \\ \bottomrule \end{tabular} -\end{table} +\end{center} -\subsubsection{table-omit-exponent} -\begin{table}[H] -\centering -\caption{The \texttt{table-omit-exponent} option} -\label{tab:exp:omit} -\begin{tabular}{ -S[table-format = 1.1e1] -S[fixed-exponent = 3, table-format = 2.1, table-omit-exponent] +Reserving space for comparators in \texttt{S} columns +\begin{center} +\sisetup{ +table-number-alignment = center, +table-format=<<2.2e2, } +\begin{tabular}{ +S +S%[table-comparator = true] +S[table-align-comparator=false]} \toprule -{Header} & {Header / \num{e3}} \\ +{Values} & {Values} & {Values} \\ \midrule -1.2e3 & 1.2e3 \\ -3e2 & 3e2 \\ -1.0e4 & 1.0e4 \\ +2 .3 & < 2.3e8 & < 2.3e8\\ +34.23 & = 34.23 & = 34.23 \\ +56.78 & >= 56.78e3 & >= 56.78e3\\ +3,76 & \gg e6 & \gg e6 \\ \bottomrule \end{tabular} -\end{table} - -\subsubsection{table-align-text-pre,table-align-text-post} -% \begin{table}[H] -% \caption{Closing notes up to text.} -% \label{tab:S:notes} -% \newrobustcmd\NoteMark[1]{% -% \textsuperscript{\emph{#1}}% -% } -% \centering -% \sisetup{ -% table-number-alignment = center, -% table-figures-integer = 2, -% table-figures-decimal = 4, -% table-space-text-pre -% = \NoteMark{a} -% } -% \begin{tabular}{ -% S -% S[table-align-text-pre = false] -% } -% \toprule -% {Values} -% & {Values} \\ -% \midrule -% 2.3456 & -% 2.3456 \\ -% \NoteMark{a} 4.234 & \NoteMark{a} 4.234 \\ -% \NoteMark{b} -% .78 -% & \NoteMark{b} -% .78 \\ -% \NoteMark{d} 88 -% & \NoteMark{d} 88 -% \\ -% \bottomrule -% \end{tabular} -% \hfil -% \sisetup{table-space-text-post = \NoteMark{a}} -% \begin{tabular}{ -% S -% S[table-align-text-post = false] -% } -% \toprule -% {Values} -% & {Values} \\ -% \midrule -% 2.3456 -% & 2.3456 \\ -% 34.234 \NoteMark{a} & 34.234 \NoteMark{a} \\ -% 56.78 -% \NoteMark{b} & 56.78 \NoteMark{b} \\ -% 90.4 -% \NoteMark{c} & 90.4 -% \NoteMark{c} \\ -% 88 -% \NoteMark{d} & 88 -% \NoteMark{d} \\ -% \bottomrule -% \end{tabular} -% \end{table} +\end{center} -\subsubsection{table-auto-round} -\begin{table}[H] -\centering -\caption{The \texttt{table-auto-round} option.} -\label{tab:S:auto} -\sisetup{ -table-number-alignment = center, -table-figures-integer = 1, -table-figures-decimal = 3 +\subsubsection{table-align-text-[before\textbar after]} + +Closing notes up to text +\begin{center} +\newrobustcmd\NoteMark[1]{% +\textsuperscript{\emph{#1}}% } -% Notice the overfull hbox which results with -% the first column -\begin{tabular}{ +\sisetup{table-format = {\NoteMark{a}}2.4} +\begin{tabular}{@{} S -S[table-auto-round] -} +S[table-align-text-before = false] +@{}} +\toprule +{Values} & {Values} \\ +\midrule +2.3456 & 2.3456 \\ +\NoteMark{a} 4.234 & \NoteMark{a} 4.234 \\ +\NoteMark{b} .78 & \NoteMark{b} .78 \\ +\NoteMark{d} 88 & \NoteMark{d} 88 \\ +\bottomrule +\end{tabular} +\qquad +\sisetup{table-format = 2.4{\NoteMark{a}}} +%\sisetup{table-format = 2.4\NoteMark{a}} % todo error +\begin{tabular}{@{} +S +S[table-align-text-after = false] +@{}} +\toprule +{Values} & {Values} \\ +\midrule +2.3456 & 2.3456 \\ +34.234 \NoteMark{a} & 34.234 \NoteMark{a} \\ +56.78 \NoteMark{b} & 56.78 \NoteMark{b} \\ +90.4 \NoteMark{c} & 90.4 \NoteMark{c} \\ +88 \NoteMark{d} & 88 \NoteMark{d} \\ +\bottomrule +\end{tabular} +\end{center} + +\subsubsection{table-auto-round} + +The \texttt{table-auto-round} option +\begin{center} +\sisetup{table-format = 1.3} +\begin{tabular}{@{}SS[table-auto-round]@{}} \toprule {Header} & {Header} \\ \midrule @@ -1260,59 +1833,104 @@ \subsubsection{table-auto-round} 1.2345 & 1.2345 \\ \bottomrule \end{tabular} -\end{table} +\end{center} \subsubsection{parse-numbers} -\begin{table}[H] -\caption{Aligning without parsing.} -\label{tab:S:nonparsed} + +Aligning without parsing +\begin{center} \sisetup{ parse-numbers = false, -table-figures-integer = 2, -table-figures-decimal = 3 +table-format = 3.3 } -\centering -\begin{tabular}{ +\begin{tabular}{@{} S S[table-number-alignment = center] S[table-number-alignment = right] S[table-number-alignment = left] -} +@{}} \toprule {Some values} & {Some values} & {Some values} & {Some values} \\ \midrule -2.35 & -2.35 & -2.35 & -2.35 \\ -34.234 & -34.234 & -34.234 & 34.234 \\ -56.783 & -56.783 & -56.783 & 56.783 \\ -3,762 & -3,762 & -3,762 & -3.762 \\ +2.35 & 2.35 & 2.35 & 2.35 \\ +34.234 & 34.234 & 34.234 & 34.234 \\ +56.783 & 56.783 & 56.783 & 56.783 \\ +3,762 & 3,762 & 3,762 & 3.762 \\ \sqrt{2} & \sqrt{2} & \sqrt{2} & \sqrt{2} \\ \bottomrule \end{tabular} -\end{table} +\end{center} + +\subsubsection{drop-exponent} + +The \texttt{drop-exponent} option +\begin{center} +\begin{tabular}{@{} +S[table-format = 1.1e1] +S[ +drop-exponent = true, +exponent-mode = fixed, +fixed-exponent = 3, +table-format = 2.1, +] +@{}} +\toprule +{Header} & \multicolumn{1}{c@{}}{Header / \num[print-unity-mantissa = false]{e3}} \\ +\midrule +1.2e3 & 1.2e3 \\ +3e2 & 3e2 \\ +1.0e4 & 1.0e4 \\ +\bottomrule +\end{tabular} +\end{center} + +\subsubsection{table-column-width, table-fixed-width} + +Fixed-width columns +\begin{center} +\begin{tabular} +{@{} +S +S[table-column-width = 2cm] +@{}} +\toprule +{Flexible} & +{Fixed} \\ +\midrule +1.23 & 1.23 \\ +45.6 & 45.6 \\ +\bottomrule +\end{tabular} +\end{center} -\subsubsection{table-text-alignment} -\begin{table}[H] -\caption{Aligning text in \texttt{S} columns.} -\label{tab:S:text} +Right-aligning under a heading +\begin{center} +\newlength\mylength +\settowidth{\mylength}{Long header} \sisetup{ -table-number-alignment = center, -table-figures-integer = 4, -table-figures-decimal = 4 +table-alignment-mode = none , +table-column-width = \mylength , +table-number-alignment = right } -\centering +\begin{tabular}{@{}S@{}} +\toprule +{Long header} \\ +\midrule +12.33 \\ +2 \\ +1234 \\ +\bottomrule +\end{tabular} +\end{center} + +\subsubsection{table-text-alignment, table-alignment} + +Aligning text in \texttt{S} columns +\begin{center} +\sisetup{table-format = 4.4} \begin{tabular}{ S S[table-text-alignment = left] @@ -1325,257 +1943,153 @@ \subsubsection{table-text-alignment} \midrule 992.435 & 992.435 & 992.435 \\ 7734.2344 & 7734.2344 & 7734.2344 \\ -56.7834 & -56.7834 & -56.7834 \\ -3,7462 & -3,7462 & -3,7462 \\ -\bottomrule -\end{tabular} -\end{table} - -\subsubsection{table-unit-alignment} -\begin{table}[H] -\centering -\caption{Alignment options in \texttt{s} columns.} -\label{tab:s:align} -\begin{tabular} -{ -s[table-unit-alignment = right] -s -s[table-unit-alignment = left] -} -\toprule -{Right-aligned} & -{Centred text} & -{Left-aligned} \\ -\midrule -\metre\per\second & \metre\per\second & \metre\per\second \\ -\kilogram -& \kilogram -& \kilogram -\\ +56.7834 & 56.7834 & 56.7834 \\ +3,7462 & 3,7462 & 3,7462 \\ \bottomrule \end{tabular} -\end{table} +\end{center} \subsubsection{table-alignment} -\subsubsection{table-column-width} -\begin{table}[H] -\centering -\caption{Fixed-width columns.} -\label{tab:width:fixed} -\begin{tabular} +\subsection{Locale Options} +\qty{1.234}{\metre}\\ +\qty[locale = DE]{6.789}{\metre} % todo spacing + +\subsection{Preamble-only options} +These are in a different file. We check that trying to change the options has no effect here: + { -s -s[table-column-width = 2 cm] -S -S[table-column-width = 2 cm] +\sisetup{ + list-input-separator=:, + product-input-separator=*, + table-column-type=T } +\numlist{1;2;3} \\ +\numproduct{1x2x3} \\ +Table check:\\ +\begin{tabular} +{@{}S +S[table-alignment-mode = none] +@{}} \toprule -{Flexible} & -{Fixed} -& -{Flexible} & -{Fixed} -\\ +{Decimal-centered} & +{Simple centering} \\ \midrule -\metre\per\second & \metre\per\second & 1.23 & 1.23 \\ -\kilogram\candela & \kilogram\candela & 45.6 & 45.6 \\ +12.345 & 12.345 \\ +6,78 & 6,78 \\ +-88.8(9) & -88.8(9) \\ +4.5e3 & 4.5e3 \\ \bottomrule \end{tabular} -\end{table} - -% \begin{table}[H] -% \centering -% \caption{Right-aligning under a heading.} -% \label{tab:width:special} -% \settowidth\mylength{Long header} -% \sisetup{ -% table-format -% = 4 -% , -% table-number-alignment = center -% , -% table-column-width -% = \mylength , -% input-decimal-markers = -% , -% input-symbols -% = . -% , -% } -% \begin{tabular}{S} -% \toprule -% {Long header} \\ -% \midrule -% 12.33 \\ -% 2 -% \\ -% 1234 -% \\ -% \bottomrule -% \end{tabular} -% \end{table} - -\end{document} - - - - - - - - - - - - - -\si{kg.m.s^{-1}}\\ -\si{\kilogram\metre\per\second} \\ -\si[per-mode=symbol]{\kilogram\metre\per\second} \\ -\si[per-mode=symbol]{\kilogram\metre\per\ampere\per\second} - -\numlist{10;20;30}\\ -\SIlist{0.13;0.67;0.80}{\milli\metre} \\ -\numrange{10}{20}\\ -\SIrange{0.13}{0.67}{\milli\metre}\\ - - -\numlist{10;30;50;70} - -\numrange{10}{30} - - -\si{kg.m/s^2} \\ -\si{g_{polymer}~mol_{cat}.s^{-1}} - -\si{\kilo\gram\metre\per\square\second} -\si{\gram\per\cubic\centi\metre} -\si{\square\volt\cubic\lumen\per\farad} -\si{\metre\squared\per\gray\cubic\lux} -\si{\henry\second} - -\SI[mode=text]{1.23}{J.mol^{-1}.K^{-1}}\\ -\SI{.23e7}{\candela}\\ -\SI[per-mode=symbol]{1.99}[\$]{\per\kilogram}\\ -\SI[per-mode=fraction]{1,345}{\coulomb\per\mole}\\ - -\SIlist{10;30;45}{\metre} - -\si{\square\becquerel} \\ -\si{\joule\squared\per\lumen} \\ -\si{\cubic\lux\volt\tesla\cubed} - -\si{\henry\tothe{5}} \\ -\si{\raiseto{4.5}\radian} - -\si{\joule\per\mole\per\kelvin} \\ -\si{\joule\per\mole\kelvin} \\ -\si{\per\henry\tothe{5}} \\ -\si{\per\square\becquerel} +} -\si{\kilogram\of{metal}} \\ -\SI[qualifier-mode = brackets] -{0.1}{\milli\mole\of{cat}\per\kilogram\of{prod}} +% these are v2 +%\subsubsection{input-product, input-quotient} +%\numproduct{1 x 2 x 3} \\ +%\numproduct[input-product=*]{4 * 5 * 6} \\ -\si[per-mode = fraction] -{\cancel\kilogram\metre\per\cancel\kilogram\per\second} \\ -\si{\highlight{red}\kilogram\metre\per\second} \\ -\si[unit-color = purple] -{\highlight{red}\kilogram\metre\per\second} +%\section{Localisation} +%This is in a different file. +\setcounter{section}{9} -\si{\kilo} \\ -\si{\micro} \\ -\si[prefixes-as-symbols = false]{\kilo} +\section{Hints for using siunitx} -\si{\kilo\gram\micro} \\ -\SI{10}{\micro} +\setcounter{subsection}{1} +\subsection{Adjusting \textbackslash litre and \textbackslash liter} +{ +\DeclareSIUnit\litre{SUCCESS} +\unit{\liter} +} +\setcounter{subsection}{4} -\begin{table} -\caption{Standard behaviour of the \texttt{S} column type.} -\label{tab:S:standard} -\centering -\begin{tabular}{S} -\toprule -{Some Values} \\ -\midrule -2.3456 \\ -34.2345 \\ --6.7835 \\ -90.473 \\ -5642.5 -\\ -1.2e3 \\ -e4 \\ -\bottomrule -\end{tabular} -\end{table} +\subsection{Expanding content in tables} -\begin{table} -\caption{Detection of surrounding material in an \texttt{S} -column.} -\label{tab:S:extras} -\centering -\begin{tabular}{S[color=orange]} +Values as macros in \texttt{S} columns +\begin{center} +\newcommand*\myvaluea{1234} +\newcommand\myvalueb{1234} +\DeclareRobustCommand*\myvaluec{1234} +\protected\def\myvalued{1234} +\begin{tabular}{@{}S@{}} \toprule {Some Values} \\ \midrule -12.34 \\ -\color{purple} 975,31 \\ -44.268 \textsuperscript{\emph{a}} \\ +\myvaluea 8.8 \myvaluea \\ % Both expanded +\myvalueb 8.8 \myvalueb \\ % First expanded by TeX +% to numbers +%\myvaluec 8.8 \myvaluec \\ % First expanded by TeX % todo error caused on next line +% but not to numbers! +\myvalued 8.8 \myvalued \\ % Neither expanded % todo output overlaps +{\myvaluea\ 8.8 \myvaluea} \\ % Neither expanded \bottomrule \end{tabular} -\end{table} +\end{center} + +% \usepackage{xfp} +%Calculated values +%\begin{center} +%\newcommand{\valuea}{66.7012} +%\newcommand{\valueb}{66.0212} +%\newcommand{\valuec}{64.9026} +%\begin{tabular}{ +%@{} +%S[table-format = 2.4] +%S[table-format = 3.4] +%@{} +%} +%\toprule +%{Value} & {Doubled} \\ +%\midrule +%\valuea & \fpeval{\valuea * 2} \\ +%\valueb & \fpeval{\valueb * 2} \\ +%\valuec & \fpeval{\valuec * 2} \\ +%\bottomrule +%\end{tabular} +%\end{center} + +\setcounter{subsection}{10} + +\subsection{Special considerations for the \texorpdfstring{\Backslash}{\textbackslash}\unit{\kWh} unit} + +\unit{\kWh} \\ +\unit{\kWh\per\metre}\\ +{ +\DeclareSIUnit\kWh{kWh} +\DeclareSIUnit\KWH{kWh} +\unit{\KWH\per\metre}\\ +\unit{kWh.m^{-1}}\\ +} +\unit{\candela\per\kWh}\\ +\unit{\candela\per\kilo\watt\per\hour} \\ +\unit[sticky-per]{\candela\per\kWh} -\begin{table} -\caption{Controlling complex alignment with the tablenum macro.} -\label{tab:tablenum} -\centering -\begin{tabular}{lr} -\toprule -Heading & Heading \\ -\midrule -Info & More info \\ -Info & More info \\ -\multicolumn{2}{c}{\tablenum[table-format = 4.4]{12,34}} -\\ -\multicolumn{2}{c}{\tablenum[table-format = 4.4]{333.5567}} \\ -\multicolumn{2}{c}{\tablenum[table-format = 4.4]{4563.21}} -\bottomrule -\end{tabular} -\hfil -\begin{tabular}{lr} -\toprule -Heading & Heading \\ -\midrule -\multirow{2}*{\tablenum{88,999}} & aaa \\ -& bbb \\ -\multirow{2}*{\tablenum{33,435}} & ccc \\ -& ddd \\ -\bottomrule -\end{tabular} -\end{table} +\subsection{Prefixes and small angles} -\begin{table} -\centering -\caption{Units in tables.} -\label{tab:s:demo} -\begin{tabular}{s} -\toprule -\multicolumn{1}{c}{Unit} \\ -\midrule -\metre\squared\per\second \\ -\pascal \\ -m.s^{-1} \\ -\bottomrule -\end{tabular} -\end{table} +{ +\DeclareSIUnit\arcsecond{as} +\qty{1e-3}{\arcsecond} \\ +\qty[prefix-mode = combine-exponent]{1e-3}{\arcsecond} +} +%\setcounter{subsection}{15} +% +%\subsubsection{Symbolic `digits'} +% +%{ +%\sisetup{input-digits = 0123456789\pi}% +%\num{4\pi e-7}\\ % fails +%\robustify\dots % fails +%\sisetup{input-digits = 0123456789\dots}% +%\qty{0,4066\dots}{\metre\squared} +%} + +\setcounter{subsection}{16} + +\subsection{Demonstrating prefixes} +\unit{\yotta\noop} \\ +\qty[prefix-mode = extract-exponent, print-unity-mantissa = false]{1}{\yotta\noop} \\ +a\unit{\noop}b \end{document} diff --git a/t/complex/si.xml b/t/complex/si.xml index 6fe21e31c..d249edbf5 100644 --- a/t/complex/si.xml +++ b/t/complex/si.xml @@ -1,9022 +1,15143 @@ + - - - + + - -

- - - + + Contents + +
+ + 1 + section 1 + 1 + §1 + + 1Introduction + +

This tries to follow the package documentation released 2025-07-09, with additional tests. Items remaining (generally ordered from hardest to easiest) are

+ + + + + item  + 1st item + + +

error: evaluate-expression, expression

+
+
+ + + + item  + 2nd item + + +

sansmath: package needed to evaluate two more tests

+
+
+ + + + item  + 3rd item + + +

The spacing in tables is not quite right. See the comment on &six_table_space

+
+
+ + + + item  + 4th item + + +

font and spacing: several instances where we should make a font change or adjust the spacing, but don’t.

+
+
+ + + + item  + 5th item + + +

detect if loaded with [=v2] or [=2021-04-09] or earlier

+
+
+
+
+ +
+ + 2 + section 2 + 2 + §2 + + <tag close=" ">2</tag>siunitx for the impatient + +

+ + 12 345.678 90 + + + + + × + 0.3 + + + 10 + 45 + + + + + - - - - 1.2 - ° + ± + 1 + + + 2 + i - - - 3 - + + + + + + × + + × + 1.654 + 2.34 + 3.430 + + +

+
+ +

+ + + + kg + m - - 4 - + + s + + - + 1 + - - - - - -Some text + + - - 4 - - - m - - - Sv - - - - 1 - + + kg + m + + + s + + - + 1 - More text + - - - 4 - - - m - - - Sv - - - - 1 - - + + / + + + kg + m + + s + + + + + + / + + + kg + m + + + + + + + + ( + + + A + s + + ) + + - Still red here! - +

+
+ +

- + - - - - + + + - 1 - , - 2 - , - 3 - and - 4 + 10 + , + 20 + and + 30 - Still red here!

-
- -

Unsemantic: - - - - - - - m - 2 - - s - - - - - - - μ - - - m - 2 - - - -

-
- -

Semantic again: - - - - - 0.094 - - - π - mm - mrad - - - -

-
- -

- - - - 0.094 - - - - - 1 - 3 + + + + + + + + - mm - mrad - - - -

-
- -

- - - - 0.094 - - + + + + 0.13 + mm + + , + + + 0.67 + mm + + and + + + 0.80 + mm + + + + + + + - / - π - mm + + + + + 10 + to + 20 + + + + + + - - mrad - 3 + + + - - - -

-
-
- - 1 - 1 - §1 - - <tag close=" ">1</tag>Numbers - - - 1.1 - 1.1 - §1.1 - - <tag close=" ">1.1</tag>General - -

+ + + + 0.13 + mm + + to + + + 0.67 + mm + + + + +

+
+ + Other tests + +

- 12 345.678 90 + + + + + + + + + 10 + , + 20 + and + 30 + + - + - - ± - 1 - - - 2 - i + + + + + + + 1.2 + ° + + + + 3 + + + + + 4 + + - + - +

+
+ +

Unsemantic: + - - × - 0.3 - - - 10 - 45 + + + + + m + 2 + s - + - × - - × - 1.654 - 2.34 + + μ + + + m + 2 - 3.430 - +

+
+ +

Semantic again: + - π + + + 0.094 + + + π + mm + mrad + + - + - - - + + + 0.094 + - 2 - π + + + 1 + 3 + + mm + mrad - + - + - / - π - 3 + + 0.094 + + + + / + π + mm + + + + mrad + 3 + + -

+

- -

+ +

+
+ + 3 + section 3 + 3 + §3 + + <tag close=" ">3</tag>Using the siunitx package + + + 3.1 + subsection 3.1 + 3.1 + §3.1 + + <tag close=" ">3.1</tag>Numbers + +

123 - + 1234 - + 12 345 - + 0.123 - + 0.1234 - + 0.123 45 - + - - × - 3.45 - + + × + 3.45 + 10 - - - - - - 4 - - + + - + 4 + - + - - - - - + + - + 10 10 -

+

- -

- - - × - 123 - - - 10 - 4 - - - - + +

- - × - - - 123 - - - - ( - 3 - ) - - - - - - 10 - 4 + + + + + + + - + + 10 + , + 30 + , + 50 + and + 70 + + -

+

- -

- - - - 123 - - - - ( - 2 - ) - - - - - + +

- ± - 123 - - - 2 - i - + × + 10 + 30 - +

+
+ +

- - + - 123 - - - 234 - i + + + + + - + + 10 + to + 30 + + - - - - × - - - - - +

+
+ + + 3.1.1 + subsubsection 3.1.1 + 3.1.1 + §3.1.1 + + <tag close=" ">3.1.1</tag>Other Tests + +

+ + + × + 123 + + + 10 + 4 - - ( - - + - 123 - - - 234 - i - - - ) - - - - - 10 - 3 - - - - - - × - - - - - + + + + + × + + + 123 + + + + ( + 3 + ) + + - - ( - - + - - - 123 - - - - ( - 1 - ) - - - - - - + + + 10 + 4 + + + +

+
+ +

+ + + + 123 + + + + ( + 2 + ) + + + + + + + + ± + 123 + + + 2 + i + + + + + + + + + 123 + + + 234 + i + + + + + + + × + + + + + + + + ( + + + + - 234 - - + 123 + + ( - 1 + 1 ) - i + + + + + 234 + + + + ( + 1 + ) + + + + i + - - ) - - - - - 10 - 3 - - - - - - - - 3 - i - - - - - - × - - - 3 - i + ) + + + + + 10 + 3 + - - - 10 - 4 + + + + + × + + + + ( + + + + + 234 + + + + ( + 1 + ) + + + + i + + ) + + + + + 10 + 3 + - - -

-
- -

Pretty nonsensical stuff? - - - - × - - + +

+
+ +

Pretty nonsensical stuff? + + + + + + + + - 1 + 1 . - π + + + + + + π + e + + 3 + - - - 10 - 3 - - - - - - 1234.1234 - - - - - + + + + 1234.1234 + + + 3 ξ - - - - - - + + + 3 ξ - - - - - - + + + 3 ξ - - - - - - + + + 3 ξ - - - - - - + + + 3 ξ - - -

-
- -

- - - - 1.23 - - - - ( - 1 - ) - - - - - - - - - 1.23 - - - - ( - 1 - ) - - - - - - - - - 1.23 - - - - ( - π - ) - - - - -

-
-
- - - 1.2 - 1.2 - §1.2 - - <tag close=" ">1.2</tag>Parsing numbers - - - 1.2.1 - 1.2.1 - §1.2.1 - - <tag close=" ">1.2.1</tag>input-digits, input-decimal-markers, input-signs, input-exponent-markers - - - - 1.2.2 - 1.2.2 - §1.2.2 - - <tag close=" ">1.2.2</tag>input-symbols, input-ignore - - - - 1.2.3 - 1.2.3 - §1.2.3 - - <tag close=" ">1.2.3</tag>input-comparators - -

- - - < - - 10 - - - - - - - - 0.12 - -

+

-
- - - 1.2.4 - 1.2.4 - §1.2.4 - - <tag close=" ">1.2.4</tag>input-open-uncertainty, input-close-uncertainty, input-uncertainty-signs - -

+ +

- 9.99 - - + 1.23 + + ( - 9 + 1 ) - + - 9.99 - - + 1.23 + + ( - 9 + 1 ) - + - - 9.99 - - + + 1.23 + + ( - 9 + π ) - +

+
+ +

- - 123.0 - - + + 1.234 + + ( - 45 + 5 ) + x + π - + - - 12.3 - - + + 1.234 + + ( - 60 + 5 ) + x + π -

+

- + - 1.2.5 - 1.2.5 - §1.2.5 + 3.1.2 + subsubsection 3.1.2 + 3.1.2 + §3.1.2 - <tag close=" ">1.2.5</tag>input-complex-roots - -

+ 3.1.2Lists and ranges of numbers + +

- - + - 9.99 - - - 88.8 - i + + + + + + - + + + + 10 + m + + , + + + 30 + m + + and + + + 45 + m + + + - + - + - 9.99 - - - 88.8 - i + × + + + 10 + m + + + + 30 + m + + + + 45 + m -

+ + + + + + + + + + + + 10 + m + + to + + + 30 + m + + + + +

- - - 1.2.6 - 1.2.6 - §1.2.6 - - <tag close=" ">1.2.6</tag>input-protect-tokens - - - - 1.2.7 - 1.2.7 - §1.2.7 - - <tag close=" ">1.2.7</tag>parse-numbers - -

- + + + + 3.2 + subsection 3.2 + 3.2 + §3.2 + + 3.2Angles + +

+ + + - - 2 + + 10 + ° - -

-
-
+ + + + + + + + + 12.3 + ° + + + + + + + + + + 4.5 + ° + + + + + + + + + + + + 1 + ° + + + + 2 + + + + + 3 + + + + + + + + + + + + 1 + + + + + + + + + + + 10 + ° + + + + + + + + + - + + + 1 + + + + + +

+
- + - 1.3 - 1.3 - §1.3 + 3.3 + subsection 3.3 + 3.3 + §3.3 - <tag close=" ">1.3</tag>Post-processing numbers - + <tag close=" ">3.3</tag>Units + - 1.3.1 - 1.3.1 - §1.3.1 + 3.3.1 + subsubsection 3.3.1 + 3.3.1 + §3.3.1 - <tag close=" ">1.3.1</tag>round-mode, round-precision - -

- - 1.234 56 - - - - 14.23 - - + 3.3.1unit + +

- - 0.123 45 - - - - ( - 9 - ) - - + / + + + kg + m + + + + s + 2 + - + - 1.234 56 + + + + + g + + + p + o + l + y + m + e + r + + + + + mol + + + c + a + t + + + + + s + + - + 1 + + + - + - 14.23 + + + kg + m + + + s + + - + 2 + + + - + - - 0.123 45 - - - - ( - 9 - ) - - + + g + + + cm + + - + 3 + + - + - 1.234 56 + + + + + V + 2 + + + + lm + 3 + + + + F + + - + 1 + + + - + - 14.23 + + + + + m + 2 + + + + Gy + + - + 1 + + + + + lx + 3 + + - + - - 0.123 45 - - - - ( - 9 - ) - - + + H + s -

+

- + - 1.3.2 - 1.3.2 - §1.3.2 + 3.3.2 + subsubsection 3.3.2 + 3.3.2 + §3.3.2 - <tag close=" ">1.3.2</tag>round-integer-to-decimal - -

+ 3.3.2qty + +

- 1 + + + 1.23 + + + J + + + mol + + - + 1 + + + + + K + + - + 1 + + + + - + - 1 + + + + × + 0.23 + + + 10 + 7 + + + cd + - - + - 1 + + + 1.99 + + / + + kg + + - + - 1 + + + 1.345 + + + C + mol + + -

+

- + - 1.3.3 - 1.3.3 - §1.3.3 + 3.3.3 + subsubsection 3.3.3 + 3.3.3 + §3.3.3 - <tag close=" ">1.3.3</tag>round-minimum - -

+ 3.3.3qtylist + +

- 0.0055 - - - - 0.0045 - - - - 0.0055 - - - - 0.0045 + + + + + + + + + + + 10 + m + + , + + + 30 + m + + and + + + 45 + m + + + -

+

- + - 1.3.4 - 1.3.4 - §1.3.4 + 3.3.4 + subsubsection 3.3.4 + 3.3.4 + §3.3.4 - <tag close=" ">1.3.4</tag>round-half - -

- - 0.055 - - - - 0.045 - - - - 0.055 - - + 3.3.4qtyproduct + +

- 0.045 + + × + + + 10 + m + + + + 30 + m + + + + 45 + m + +

- + - 1.3.5 - 1.3.5 - §1.3.5 + 3.3.5 + subsubsection 3.3.5 + 3.3.5 + §3.3.5 - <tag close=" ">1.3.5</tag>add-decimal-zero, add-integer-zero - -

- - 123.0 - - - - 456 - - - - 0.789 - - + 3.3.5qtyrange + +

- - - 123 - . + + + + + + + + + 10 + m + + to + + + 30 + m + - - - 456 - - - - .789 - -

-
-
- - - 1.3.6 - 1.3.6 - §1.3.6 - - <tag close=" ">1.3.6</tag>minimum-integer-digits - -

- - 123 - - - - 123 - - - - 123 - - - - 123 - - - - 123 - -

+

- - - 1.3.7 - 1.3.7 - §1.3.7 - - <tag close=" ">1.3.7</tag>explicit-sign, retain-explicit-plus - -

- - 345 - - - - - + + + + 3.4 + subsection 3.4 + 3.4 + §3.4 + + 3.4Complex numbers and quantities + +

+ + + × + - + - 345 + + + + + ( + + + + 123 + + + 234 + i + + + ) + - - - - - + + + 10 + 3 + + + + + + + × + - - - 345 + + + + + ( + + + + + + 123 + + + + ( + 1 + ) + + + + + + + + 234 + + + + ( + 1 + ) + + + + i + + + ) + - - - - 345 - -

-
-
- - - 1.3.8 - 1.3.8 - §1.3.8 - - <tag close=" ">1.3.8</tag>retain-unity-mantissa, retain-zero-exponent - -

- - - × - 1 - - - 10 - 4 - - - - - - - × - 1 - - - 10 - 4 - + + + 10 + 3 - - - - 444 - - - - - × - 444 - - - 10 - 0 - + + + + + + + + + 3 + i - -

-
-
- - - 1.3.9 - 1.3.9 - §1.3.9 - - <tag close=" ">1.3.9</tag>scientific-notation, fixed-exponent - -

- - 0.001 - - - - 0.0100 - - - - 1200 - - - - 0.001 - - - - 0.0100 - - - - 1200 - - - - 0.001 - - - - 0.0100 - - - - 1200 - - - - 0.001 - - - - 0.0100 - - - - 1200 - -

-
-
- - - 1.3.10 - 1.3.10 - §1.3.10 - - <tag close=" ">1.3.10</tag>omit-uncertainty - -

- + + + + + + - - 0.01 - - + × + + ( - 2 + + + 3 + i + ) + + + 10 + 4 + - - - - 0.01 - -

-
-
+ + +

+
- + - 1.4 - 1.4 - §1.4 + 3.5 + subsection 3.5 + 3.5 + §3.5 - <tag close=" ">1.4</tag>Printing numbers - - - 1.4.1 - 1.4.1 - §1.4.1 - - <tag close=" ">1.4.1</tag>group-digits, group-four-digits,group-seperator - -

- - 12 345.678 90 - - - - 12345.67890 - - - - 12345.678 90 - - - - 12 345.67890 - -

-
- -

- - 12345.67890 - - - - 12345.678 90 - - - - 12 345.67890 - -

-
- -

- - 1 234 567 890.123 456 789 0 - - - - 1 234 567 890.123 456 789 0 - -

-
- -

- - 12 345 - - - - - - - 12 - , - 345 - - - - - - - - - - 12 -   - 345 - - - -

-
-
- - - 1.4.2 - 1.4.2 - §1.4.2 - - <tag close=" ">1.4.2</tag>group-minimum-digits - -

- - 1234 - - - - 1 234 - - - + 3.5The unit macros + +

The SI base units:

+ + + + Unit + Macro + Symbol + + + + + ampere + \ampere + + + A + + + + + candela + \candela + + + cd + + + + + kelvin + \kelvin + + + K + + + + + kilogram + \kilogram + + + kg + + + + + metre + \metre + + + m + + + + + mole + \mole + + + mol + + + + + second + \second + + + s + + + + + +
+ +

The coherent derived units:

+ + + + Unit + Macro + Symb + Unit + Macro + Symb + + + + + becquerel + \becquerel + + + Bq + + + newton + \newton + + + N + + + + + degreeCelsius + \degreeCelsius + + + °C + + + ohm + \ohm + + + + + + + + coulomb + \coulomb + + + C + + + pascal + \pascal + + + Pa + + + + + farad + \farad + + + F + + + radian + \radian + + + rad + + + + + gray + \gray + + + Gy + + + siemens + \siemens + + + S + + + + + hertz + \hertz + + + Hz + + + sievert + \sievert + + + Sv + + + + + henry + \henry + + + H + + + steradian + \steradian + + + sr + + + + + joule + \joule + + + J + + + tesla + \tesla + + + T + + + + + katal + \katal + + + kat + + + volt + \volt + + + V + + + + + lumen + \lumen + + + lm + + + watt + \watt + + + W + + + + + lux + \lux + + + lx + + + weber + \weber + + + Wb + + + + + +
+ +

The non-SI units:

+ + + + Unit + Macro + Symbol + + + + + astronomicalunit + \astronomicalunit + + + au + + + + + bel + \bel + + + B + + + + + dalton + \dalton + + + Da + + + + + day + \day + + + d + + + + + decibel + \decibel + + + dB + + + + + degree + \degree + + + ° + + + + + electronvolt + \electronvolt + + + eV + + + + + hectare + \hectare + + + ha + + + + + hour + \hour + + + h + + + + + litre + \litre + + + l + + + + + liter + \liter + + + L + + + + + arcminute + \arcminute + + + + + + + + minute + \minute + + + min + + + + + arcsecond + \arcsecond + + + + + + + + neper + \neper + + + Np + + + + + tonne + \tonne + + + t + + + + + +
+ +

SI prefixes:

+ + + + Prefix + Cmd + Symb + Power + Prefix + Cmd + Symb + Power + + + + + quecto + \quecto + + + q + + + + + + + + + 10 + + - + 30 + + + + + + + deca + \deca + + + da + + + + + + + + + 10 + 1 + + + + + + + + ronto + \ronto + + + r + + + + + + + + + 10 + + - + 27 + + + + + + + hecto + \hecto + + + h + + + + + + + + + 10 + 2 + + + + + + + + yocto + \yocto + + + y + + + + + + + + + 10 + + - + 24 + + + + + + + kilo + \kilo + + + k + + + + + + + + + 10 + 3 + + + + + + + + zepto + \zepto + + + z + + + + + + + + + 10 + + - + 21 + + + + + + + mega + \mega + + + M + + + + + + + + + 10 + 6 + + + + + + + + atto + \atto + + + a + + + + + + + + + 10 + + - + 18 + + + + + + + giga + \giga + + + G + + + + + + + + + 10 + 9 + + + + + + + + femto + \femto + + + f + + + + + + + + + 10 + + - + 15 + + + + + + + tera + \tera + + + T + + + + + + + + + 10 + 12 + + + + + + + + pico + \pico + + + p + + + + + + + + + 10 + + - + 12 + + + + + + + peta + \peta + + + P + + + + + + + + + 10 + 15 + + + + + + + + nano + \nano + + + n + + + + + + + + + 10 + + - + 9 + + + + + + + exa + \exa + + + E + + + + + + + + + 10 + 18 + + + + + + + + micro + \micro + + + µ + + + + + + + + + 10 + + - + 6 + + + + + + + zetta + \zetta + + + Z + + + + + + + + + 10 + 21 + + + + + + + + milli + \milli + + + m + + + + + + + + + 10 + + - + 3 + + + + + + + yotta + \yotta + + + Y + + + + + + + + + 10 + 24 + + + + + + + + centi + \centi + + + c + + + + + + + + + 10 + + - + 2 + + + + + + + ronna + \ronna + + + R + + + + + + + + + 10 + 27 + + + + + + + + deci + \deci + + + d + + + + + + + + + 10 + + - + 1 + + + + + + + quetta + \quetta + + + Q + + + + + + + + + 10 + 30 + + + + + + + + +
+ +

+ + + + Bq + 2 + + + + + + + + + J + 2 + + + + lm + + - + 1 + + + + + + + + + + + lx + 3 + + V + + + T + 3 + + + + + + + + H + 5 + + + + + + + rad + 4.5 + + + + + + + J + + + mol + + - + 1 + + + + + K + + - + 1 + + + + + + + + + J + + + mol + + - + 1 + + + K + + + + + + + H + + - + 5 + + + + + + + + Bq + + - + 2 + + + + + + + + kg + metal + + + + + + + 0.1 + + + + + mmol + + + + ( + cat + ) + + + + + + + + kg + + + + ( + prod + ) + + + + + - + 1 + + + + + + + + + + + + + + kg + + m + + + + + + kg + + s + + + + + + + + kg + m + + + s + + - + 1 + + + + + + + + + kg + m + + + s + + - + 1 + + + + +

+
+
+ + + 3.6 + subsection 3.6 + 3.6 + §3.6 + + <tag close=" ">3.6</tag>Unit abbreviations + +

Abbreviated units

+
+ + + + + + Unit + Abbreviation + Symbol + + + + + femtogram + \fg + + + fg + + + + + picogram + \pg + + + pg + + + + + nanogram + \ng + + + ng + + + + + microgram + \ug + + + + + µ + g + + + + + + milligram + \mg + + + mg + + + + + gram + \g + + + g + + + + + kilogram + \kg + + + kg + + + + + + + + + Unit + Abbreviation + Symbol + + + + + picometre + \pm + + + pm + + + + + nanometre + \nm + + + nm + + + + + micrometre + \um + + + + + µ + m + + + + + + millimetre + \mm + + + mm + + + + + centimetre + \cm + + + cm + + + + + decimetre + \dm + + + dm + + + + + metre + \m + + + m + + + + + kilometre + \km + + + km + + + + + + + + + Unit + Abbreviation + Symbol + + + + + picometer + \pm + + + pm + + + + + nanometer + \nm + + + nm + + + + + micrometer + \um + + + + + µ + m + + + + + + millimeter + \mm + + + mm + + + + + centimeter + \cm + + + cm + + + + + decimeter + \dm + + + dm + + + + + meter + \m + + + m + + + + + kilometer + \km + + + km + + + + + + + + + Unit + Abbreviation + Symbol + + + + + attosecond + \as + + + as + + + + + femtosecond + \fs + + + fs + + + + + picosecond + \ps + + + ps + + + + + nanosecond + \ns + + + ns + + + + + microsecond + \us + + + + + µ + s + + + + + + millisecond + \ms + + + ms + + + + + second + \s + + + s + + + + + + + + + Unit + Abbreviation + Symbol + + + + + femtomole + \fmol + + + fmol + + + + + picomole + \pmol + + + pmol + + + + + nanomole + \nmol + + + nmol + + + + + micromole + \umol + + + + + µ + mol + + + + + + millimole + \mmol + + + mmol + + + + + mole + \mol + + + mol + + + + + kilomole + \kmol + + + kmol + + + + + + + + + Unit + Abbreviation + Symbol + + + + + picoampere + \pA + + + pA + + + + + nanoampere + \nA + + + nA + + + + + microampere + \uA + + + + + µ + A + + + + + + milliampere + \mA + + + mA + + + + + ampere + \A + + + A + + + + + kiloampere + \kA + + + kA + + + + + + + + + Unit + Abbreviation + Symbol + + + + + microlitre + \ul + + + + + µ + l + + + + + + millilitre + \ml + + + ml + + + + + litre + \l + + + l + + + + + hectolitre + \hl + + + hl + + + + + + + + + Unit + Abbreviation + Symbol + + + + + microliter + \uL + + + + + µ + L + + + + + + milliliter + \mL + + + mL + + + + + liter + \L + + + L + + + + + hectoliter + \hL + + + hL + + + + + + + + + Unit + Abbreviation + Symbol + + + + + millihertz + \mHz + + + mHz + + + + + hertz + \Hz + + + Hz + + + + + kilohertz + \kHz + + + kHz + + + + + megahertz + \MHz + + + MHz + + + + + gigahertz + \GHz + + + GHz + + + + + terahertz + \THz + + + THz + + + + + + + + + Unit + Abbreviation + Symbol + + + + + millinewton + \mN + + + mN + + + + + newton + \N + + + N + + + + + kilonewton + \kN + + + kN + + + + + meganewton + \MN + + + MN + + + + + + + + + Unit + Abbreviation + Symbol + + + + + pascal + \Pa + + + Pa + + + + + kilopascal + \kPa + + + kPa + + + + + megapascal + \MPa + + + MPa + + + + + gigapascal + \GPa + + + GPa + + + + + + + + + Unit + Abbreviation + Symbol + + + + + milliohm + \mohm + + + + + m + + + + + + + kiloohm + \kohm + + + + + k + + + + + + + megaohm + \Mohm + + + + + M + + + + + + + + + + + Unit + Abbreviation + Symbol + + + + + picovolt + \pV + + + pV + + + + + nanovolt + \nV + + + nV + + + + + microvolt + \uV + + + + + µ + V + + + + + + millivolt + \mV + + + mV + + + + + volt + \V + + + V + + + + + kilovolt + \kV + + + kV + + + + + + + + + Unit + Abbreviation + Symbol + + + + + nanowatt + \nW + + + nW + + + + + microwatt + \uW + + + + + µ + W + + + + + + milliwatt + \mW + + + mW + + + + + watt + \W + + + W + + + + + kilowatt + \kW + + + kW + + + + + megawatt + \MW + + + MW + + + + + gigawatt + \GW + + + GW + + + + + + + + + Unit + Abbreviation + Symbol + + + + + microjoule + \uJ + + + + + µ + J + + + + + + millijoule + \mJ + + + mJ + + + + + joule + \J + + + J + + + + + kilojoule + \kJ + + + kJ + + + + + + + + + Unit + Abbreviation + Symbol + + + + + millielectronvolt + \meV + + + meV + + + + + electronvolt + \eV + + + eV + + + + + kiloelectronvolt + \keV + + + keV + + + + + megaelectronvolt + \MeV + + + MeV + + + + + gigaelectronvolt + \GeV + + + GeV + + + + + teraelectronvolt + \TeV + + + TeV + + + + + + + + + Unit + Abbreviation + Symbol + + + + + kilowatt hour + \kWh + + + + + kW + h + + + + + + + + + + Unit + Abbreviation + Symbol + + + + + femtofarad + \fF + + + fF + + + + + picofarad + \pF + + + pF + + + + + nanofarad + \nF + + + nF + + + + + microfarad + \uF + + + + + µ + F + + + + + + millifarad + \mF + + + mF + + + + + farad + \F + + + F + + + + + + + + + Unit + Abbreviation + Symbol + + + + + femtohenry + \fH + + + fH + + + + + picohenry + \pH + + + pH + + + + + nanohenry + \nH + + + nH + + + + + microhenry + \uH + + + + + µ + H + + + + + + millihenry + \mH + + + mH + + + + + henry + \H + + + H + + + + + + + + + Unit + Abbreviation + Symbol + + + + + nanocoulomb + \nC + + + nC + + + + + microcoulomb + \uC + + + + + µ + C + + + + + + millicoulomb + \mC + + + mC + + + + + coulomb + \C + + + C + + + + + + + + + Unit + Abbreviation + Symbol + + + + + microtesla + \uT + + + + + µ + T + + + + + + millitesla + \mT + + + mT + + + + + tesla + \T + + + T + + + + + + + + + Unit + Abbreviation + Symbol + + + + + kelvin + \K + + + K + + + + + + + + + Unit + Abbreviation + Symbol + + + + + decibel + \dB + + + dB + + + + + + + + +

Binary prefixes:

+ + + + Prefix + Command + Symbol + Power + + + + + kibi + \kibi + + + Ki + + + 10 + + + mebi + \mebi + + + Mi + + + 20 + + + gibi + \gibi + + + Gi + + + 30 + + + tebi + \tebi + + + Ti + + + 40 + + + pebi + \pebi + + + Pi + + + 50 + + + exbi + \exbi + + + Ei + + + 60 + + + zebi + \zebi + + + Zi + + + 70 + + + yobi + \yobi + + + Yi + + + 80 + + + +
+
+ + + 3.7 + subsection 3.7 + 3.7 + §3.7 + + <tag close=" ">3.7</tag>Creating new macros + +

+ + + + 67 890 + ° + + + + + + + 67 890 + ° + + +

+
+ +

+ + + + kg + 4 + + + + + + + m + 4 + + +

+
+ +

+ + + + 1.234 + + + + + g + pol + + + + + + mol + cat + + + - + 1 + + + + + h + + - + 1 + + + + + +

+
+ + + 3.7.1 + subsubsection 3.7.1 + 3.7.1 + §3.7.1 + + <tag close=" ">3.7.1</tag>Other Tests + +

+ + kg + + + + + kg + + + + + + + km + + + + + + + + kg + +

+
+ +

+ + a + + + + a + + + + a + + + + e + + + + e + +

+
+ +

+ + a + + + + a + +

+
+ +

+ + km + +

+
+ +

+ + + + kg + m + + + s + + - + 1 + + + + + + + + + kg + m + + + s + + - + 1 + + + + + + + + + kg + m + + + s + + - + 1 + + + + + + + + + kg + m + + + s + + - + 1 + + + + + + + + + kg + m + + + s + + - + 1 + + + + +

+
+ +

+ + + + + + kg + + m + + + s + + - + 1 + + + + + + + + + kg + + + m + + + + s + + - + 1 + + + + + + + + + kg + + + m + + + + s + + - + 1 + + + + + + + + + kg + m + + + + + s + + - + 1 + + + + + + + + + + kg + m + + + + + s + + - + 1 + + + + + +

+
+
+
+ + + 3.8 + subsection 3.8 + 3.8 + §3.8 + + <tag close=" ">3.8</tag>Tabular material + +

Standard behaviour of the S column type

+ + + + Some Values + + + + + + + 2.3456 + + + + + + + 34.2345 + + + + + + + + - + 6.7835 + + + + + + + + 90.473 + + + + + + + 5642.5 + + + + + + + + × + + + 1.2 + + + + + 10 + 3 + + + + + + + + + + + 10 + 4 + + + + + + +
+ +

Detection of surrounding material in an S column

+ + + + Some Values + + + + + + + 12.34 + + + + + + + 975.31 + + + + + + + 44.268 + + a + + + +
+ +

Text before and after numbers

+ + + + Values + + + + + 2.3456 + + + + + + + 34.2345 + + a + + + + + 34.2345 + + a + + + + + 56.7835 + + + + + now  + + 90.473 + + + + + +
+ +

Controlling complex alignment with the tablenum macro

+ + + + Heading + Heading + + + Info + More info + + + Info + More info + + + + + + + 12.34 + + + + + + + 333.5567 + + + + + + + 4563.21 + + + + + + + + + Heading + Heading + + + + + + + 88.999 + + + aaa + + + bbb + + + + + 33.435 + + + ccc + + + ddd + + + +
+
+
+
+ + 4 + section 4 + 4 + §4 + + <tag close=" ">4</tag>Package control options + + + 4.2 + subsection 4.2 + 4.2 + §4.2 + + <tag close=" ">4.2</tag>Printing + + + 4.2.1 + subsubsection 4.2.1 + 4.2.1 + §4.2.1 + + <tag close=" ">4.2.1</tag>mode, number-mode, unit-mode + + + + 4.2.2 + subsubsection 4.2.2 + 4.2.2 + §4.2.2 + + <tag close=" ">4.2.2</tag>reset-text-[family|series|shape] + +

+ + 1234 + + + + 1234 + + + + 1234 + + + + + 1234 + + + + 1234 + + + + 1234 + +

+
+
+ + + 4.2.3 + subsubsection 4.2.3 + 4.2.3 + §4.2.3 + + <tag close=" ">4.2.3</tag>propagate-math-font, reset-math-version + +

+ + kg + + + + kg + + + + + kg + + + + kg + +

+
+
+ + + 4.2.4 + subsubsection 4.2.4 + 4.2.4 + §4.2.4 + + <tag close=" ">4.2.4</tag>text-[family|series]-to-math + +

+ + kg + + + + kg + + + + + kg + + + + kg + +

+
+
+ + + 4.2.5 + subsubsection 4.2.5 + 4.2.5 + §4.2.5 + + <tag close=" ">4.2.5</tag>text-font-command + +

+ + + + 123 456 789 + + + kV + + + cm + + - + 1 + + + + + + + + + + + 123 456 789 + + + kV + + + cm + + - + 1 + + + + + +

+
+
+ + + 4.2.6 + subsubsection 4.2.6 + 4.2.6 + §4.2.6 + + <tag close=" ">4.2.6</tag>text-[sub|super]script-command + +

+ + + + kg + polymer + + + + + + + + + + kg + polymer + + +

+
+
+ + + 4.2.7 + subsubsection 4.2.7 + 4.2.7 + §4.2.7 + + <tag close=" ">4.2.7</tag>color, number-color, unit-color + +

Some text + + + + 4 + kg + + + More text + + + + 4 + kg + + + + + + + 4 + kg + + + + + + + 4 + kg + + + Still red here!

+
+ +

+ + + + 1 + g + + + + + + + 1 + g + + + + + + + 1 + g + + + + + + + 1 + g + + + + + + + + - + + + + + 1 + ° + + + + 2 + + + + + 3 + + + + + + + + + + + + + + + + + 1 + , + 2 + and + 3 + + + + + + + by + 1 + 2 + + + + + + + + + + + + 1 + to + 2 + + + +

+
+ +

+ + + × + + + 1.234 + + + + ( + 5 + ) + + + + + + 6.78 + + + + ( + 9 + ) + + + + + +

+
+
+
+ + + 4.3 + subsection 4.3 + 4.3 + §4.3 + + <tag close=" ">4.3</tag>Parsing numbers + + + 4.3.1 + subsubsection 4.3.1 + 4.3.1 + §4.3.1 + + <tag close=" ">4.3.1</tag>input-digits, input-ignore + +

+ + 1245 + +

+
+
+ + + 4.3.2 + subsubsection 4.3.2 + 4.3.2 + §4.3.2 + + <tag close=" ">4.3.2</tag>input-comparators + +

+ + + < + + 10 + + + + + + + + + + 5 + + m + + + + + + + + 0.12 + + +

+
+
+ + + 4.3.3 + subsubsection 4.3.3 + 4.3.3 + §4.3.3 + + <tag close=" ">4.3.3</tag>input-[open|close]-uncertainty, input-uncertainty-signs + +

+ + + + 9.99 + + + + ( + 9 + ) + + + + + + + + + 9.99 + + + + ( + 9 + ) + + + + + + + + + 9.99 + + + + ( + 9 + ) + + + + + + + + + 123.0 + + + + ( + 45 + ) + + + + + + + + + 12.3 + + + + ( + 60 + ) + + + + + + + + + 123.4 + + + + ( + 12 + ) + + + + + + + + + 123.4 + + + + ( + 12 + ) + + + + + + + + ± + 123.4 + 1.2 + 4.5 + + + + + + ± + 123.4 + 1.2 + 4.5 + + +

+
+
+ + + 4.3.4 + subsubsection 4.3.4 + 4.3.4 + §4.3.4 + + <tag close=" ">4.3.4</tag>input-uncertainty-divider + +

+ + + + + + + + + + + + + 10.56 + + + + 0.12 + + + + - + 0.34 + + + + + + + + + + + + + + + + + + 123.4 + + + + 4.6 + + + + - + 7.8 + + + + + + + + + + + + + + + + + + + + + 10.56 + + + + 0.01 + + + + - + 0.02 + + + + ± + 0.03 + + + + + + + + + + + + + + + + + 6.45 + + + + + + ± + 0.02 + + + + + 0.03 + + + + - + 0.04 + + + + + +

+
+ +

Also: + + + + + + + + + + + + + 5.6 + + + + 1.2 + + + + - + 3.4 + + + + + + + + + + + + + + + + + + 78.56 + + + + 0.12 + + + + - + 0.34 + + + + + + + + ± + 123.4 + 1.2 + 4.5 + 6.7 + + + + + + ± + 123.4 + 1.2 + 4.5 + 6.7 + + +

+
+
+ + + 4.3.5 + subsubsection 4.3.5 + 4.3.5 + §4.3.5 + + <tag close=" ">4.3.5</tag>parse-numbers + +

+ + + + 2 + + + + + + + + + 3 + + m + + +

+
+
+ + Other tests + +

+ + π + + + + + + 2 + π + + + + + + / + π + 3 + + +

+
+
+ + + 4.3.6 + subsubsection 4.3.6 + 4.3.6 + §4.3.6 + + <tag close=" ">4.3.6</tag>retain-explicit-decimal-marker, retain-explicit-plus, retain-negative-zero, retain-zero-uncertainty + +

+ + + + 345 + + + + + + + + 345 + + + + + 0 + + + + + - + 0 + + + + + 12.3 + + + + + + 12.3 + + + + ( + 0 + ) + + + + +

+
+ +

+ + 456 + + + + 0.789 + + + + 456 + + + + .789 + +

+
+
+
+ + + 4.4 + subsection 4.4 + 4.4 + §4.4 + + <tag close=" ">4.4</tag>Post-processing numbers + + + 4.4.1 + subsubsection 4.4.1 + 4.4.1 + §4.4.1 + + <tag close=" ">4.4.1</tag>exponent-mode, fixed-exponent + +

+ + 0.001 + + + + 0.0100 + + + + 1200 + + + + + × + 1 + + + 10 + + - + 3 + + + + + + + + × + 1.00 + + + 10 + + - + 2 + + + + + + + + × + 1.200 + + + 10 + 3 + + + + + + + × + 1 + + + 10 + + - + 3 + + + + + + + + × + 10.0 + + + 10 + + - + 3 + + + + + + + + × + 1.200 + + + 10 + 3 + + + + + + + × + 0.000 01 + + + 10 + 2 + + + + + + + × + 0.000 100 + + + 10 + 2 + + + + + + + × + 12.00 + + + 10 + 2 + + + + + + + + × + 1.23 + + + 10 + 4 + + + + + + 12 300 + +

+
+ +

+ + + + + + + + + ( + + + + 0.5 + + + 1000 + i + + + ) + + + +

+
+
+ + + 4.4.2 + subsubsection 4.4.2 + 4.4.2 + §4.4.2 + + <tag close=" ">4.4.2</tag>exponent-thresholds + +

This is unique to version 3.

+
+
+ + + 4.4.3 + subsubsection 4.4.3 + 4.4.3 + §4.4.3 + + <tag close=" ">4.4.3</tag>drop-exponent, drop-uncertainty + +

+ + + + 0.01 + + + + ( + 2 + ) + + + + + + + 0.01 + + + + + × + 0.01 + + + 10 + 3 + + + + + + 0.01 + +

+
+
+ + + 4.4.4 + subsubsection 4.4.4 + 4.4.4 + §4.4.4 + + <tag close=" ">4.4.4</tag>round-mode, round-precision, round-pad + +

+ + 1.234 56 + + + + 14.23 + + + + + + 0.123 45 + + + + ( + 9 + ) + + + + + + + 0.001 234 5 + + places: + + 1.235 + + + + 14.230 + + + + + + 0.123 45 + + + + ( + 9 + ) + + + + + + + 0.001 + + figures: + + 1.23 + + + + 14.2 + + + + + + 0.123 45 + + + + ( + 9 + ) + + + + + + + 10 000 + + + + 0.001 23 + + uncertainty: + + + + 0.123 45 + + + + ( + 9 + ) + + + + + + + + + 0.1235 + + + + ( + 2 + ) + + + + + + + + + 0.123 + + + + ( + 2 + ) + + + + + + + + + 12 300 + + + + ( + 100 + ) + + + + + + + + + 123.46 + + + + ( + 1 + ) + + + + + + + + + 1230 + + + + ( + 10 + ) + + + + + + + + + 1235 + + + + ( + 1 + ) + + + + + + + + + 10 + + + + ( + 1 + ) + + + + + + + + + 100 + + + + ( + 10 + ) + + + + + +figures: + + 12.30 + + + + 12.34 + + + + 12.3 + + +Also + + + × + + × + 0.12 + 0.46 + + 0.79 + + +

+
+
+ + + 4.4.5 + subsubsection 4.4.5 + 4.4.5 + §4.4.5 + + <tag close=" ">4.4.5</tag>round-direction, round-half + +

+ + 0.05 + + + + 0.05 + + + + 0.05 + + + + 0.04 + + + + 0.06 + + + + 0.05 + + + + + + 0.06 + + + + 0.05 + + + + 0.06 + + + + 0.04 + +

+
+
+ + + 4.4.6 + subsubsection 4.4.6 + 4.4.6 + §4.4.6 + + <tag close=" ">4.4.6</tag>uncertainty-round-direction + +

+ + + + 0.123 + + + + ( + 41 + ) + + + + + + + + + 0.123 + + + + ( + 41 + ) + + + + + + + + + 0.12 + + + + ( + 5 + ) + + + + +

+
+
+ + + 4.4.7 + subsubsection 4.4.7 + 4.4.7 + §4.4.7 + + <tag close=" ">4.4.7</tag>round-minimum + +

+ + 0.01 + + + + 0.00 + + + + 0.00 + + + + 0.01 + + + + + < + + 0.01 + + + + + + > + + + - + 0.01 + + + + + + + < + + 0.01 + + +

+
+
+ + + 4.4.8 + subsubsection 4.4.8 + 4.4.8 + §4.4.8 + + <tag close=" ">4.4.8</tag>round-zero-positive + +

+ + 0.00 + + + + + - + 0.00 + + +

+
+
+ + + 4.4.9 + subsubsection 4.4.9 + 4.4.9 + §4.4.9 + + <tag close=" ">4.4.9</tag>drop-zero-decimal + +

+ + 2.0 + + + + 2.1 + + + + + 2 + + + + 2.1 + +

+
+
+ + + 4.4.10 + subsubsection 4.4.10 + 4.4.10 + §4.4.10 + + <tag close=" ">4.4.10</tag>minimum-decimal-digits, minimum-integer-digits + +

+ + 123 + + + + 123 + + + + 0123 + + + + 0.123 + + + + 0.123 + + + + 0.1230 + +

+
+
+ + + 4.4.11 + subsubsection 4.4.11 + 4.4.11 + §4.4.11 + + <tag close=" ">4.4.11</tag>Other Tests + +

+ + 1 + + + + 456 + + + + 0.789 + + + + 456 + + + + .789 + + +Also: + + 1.00 + + + + 1.0 + + + + 1.00 + +

+
+ +

+ + + - + + ± + 52.0 + 0.4 + + + +

+
+
+
+ + + 4.5 + subsection 4.5 + 4.5 + §4.5 + + <tag close=" ">4.5</tag>Printing Numbers + + + 4.5.1 + subsubsection 4.5.1 + 4.5.1 + §4.5.1 + + <tag close=" ">4.5.1</tag>group-digits, group-separator + +

+ + 12 345.678 90 + + + + 12345.67890 + + + + 12345.678 90 + + + + 12 345.67890 + + + + 12 345 + + + + + + + 12 + , + 345 + + + + + + + + + + 12 +   + 345 + + + + + + 12 345 + +

+
+
+ + + 4.5.2 + subsubsection 4.5.2 + 4.5.2 + §4.5.2 + + <tag close=" ">4.5.2</tag>group-minimum-digits + +

+ + 1234 + + + + 12 345 + + + + 1234 + + + + 12 345 + + + + 1234.5678 + + + + 12 345.678 90 + + + + 1234.5678 + + + + 12 345.678 90 + +

+
+
+ + Other tests + +

+ + 1234 + + + + 1 234 + + + 1234.5678 - + + + 1 234.567 8 + +

+
+
+ + + 4.5.3 + subsubsection 4.5.3 + 4.5.3 + §4.5.3 + + <tag close=" ">4.5.3</tag>digit-group-size, digit-group-first-size, digit-group-other-size + +

+ + 1 234 567 890 + + + + 12345 67890 + + + + 1 23 45 67 890 + +

+
+
+ + Other tests + +

+ + 1 234 567 890.123 456 789 0 + + + + 12 3456 7890.1234 5678 90 + + + + 1 23 45 67890 + + + + 12345 67890 + + + + 123 45678 90 + + + + 12345 67890 + +

+
+
+ + + 4.5.4 + subsubsection 4.5.4 + 4.5.4 + §4.5.4 + + <tag close=" ">4.5.4</tag>output-decimal-marker + +

+ + 1.23 + + + + + + + 1 + , + 23 + + + +

+
+
+ + + 4.5.5 + subsubsection 4.5.5 + 4.5.5 + §4.5.5 + + <tag close=" ">4.5.5</tag>exponent-base, exponent-product + +

+ + + × + 1 + + + 10 + 2 + + + + + + + + 1 + + + 10 + 2 + + + + + + + × + 1 + + + 2 + 2 + + + +

+
+
+ + + 4.5.6 + subsubsection 4.5.6 + 4.5.6 + §4.5.6 + + <tag close=" ">4.5.6</tag>output-exponent-marker + +

+ + + + 1 + + + e + 2 + + + + + + + + 1 + + + e + 2 + + + + + + + + 1 + + + E + 2 + + + + + + + + 1 + + + E + 2 + + + +

+
+
+ + + 4.5.7 + subsubsection 4.5.7 + 4.5.7 + §4.5.7 + + <tag close=" ">4.5.7</tag>uncertainty-[mode|separator], output-[open|close]-uncertainty + +

+ + + + 123.45 + + + + ( + 120 + ) + + + + + + + + + 0.035 + + + + ( + 14 + ) + + + + + + + + + + 123.45 + + + + ( + 1.20 + ) + + + + + + + + + 0.035 + + + + ( + 0.014 + ) + + + + + + + + + + 123.45 + + + + ( + 1.20 + ) + + + + + + + + + 0.035 + + + + ( + 14 + ) + + + + + + + + + 1.234 + + + + + + + [ + 5 + ] + + + + + + + + + 1.234 + + + + + + + [ + 5 + ] + + + + + + + + ± + 1.234 + 0.005 + + + + + + ± + 1.234 + 0.005 + + + + + + + 8.2 + + + + + + + [ + 1.3 + ] + + + + + + + + + 8.2 + + + + + + + [ + 1.3 + ] + + + + + + + + ± + 8.2 + 1.3 + + + + + + ± + 8.2 + 1.3 + + + + + + + 1.200 + + + + + + + [ + 1 + ] + + + + + + + + ± + 1.2 + 0.001 + + + + +

+ + + ± + 67 890 + 12 345 + + +

+

+ + + ± + 67 890 + 12 345 + + +

+

+
+
+ + + 4.5.8 + subsubsection 4.5.8 + 4.5.8 + §4.5.8 + + <tag close=" ">4.5.8</tag>uncertainty-descriptors, uncertainty-descriptor-mode, uncertainty-descriptor-separator + +

+ + + ± + 1.2 + 0.3 + 0.4 + + + + + + + + + + + + + + ± + 1.2 + + + 0.3 + + ( + + + s + y + s + + ) + + + + + 0.4 + + ( + + + s + t + a + t + + ) + + + + + + + + + + + + + + + + ± + 1.2 + + + 0.3 + + + s + y + s + + + + + 0.4 + + + s + t + a + t + + + + + + + + + + + + + + + + ± + 1.2 + + + 0.3 + + ( + + + s + y + s + + ) + + + + + 0.4 + + ( + + + s + t + a + t + + ) + + + + + + + + + + + + + + + + ± + 1.2 + + + 0.3 + s + y + s + + + + 0.4 + s + t + a + t + + + + + + + + ± + 1.2 + 0.3 + + + + + + + + + + + + + + ± + 1.2 + + + 0.3 + + ( + + + s + y + s + + ) + + + + + 0.4 + + ( + + + s + t + a + t + + ) + + + 0.5 + + + + + + + + ± + 1.2 + 0.3 + + + + + + + + + + + + + ± + 1.2 + + + 0.3 + + ( + + + s + y + s + + ) + + + + + 0.4 + + ( + + + s + t + a + t + + ) + + + + + +

+
+
+ + + 4.5.9 + subsubsection 4.5.9 + 4.5.9 + §4.5.9 + + <tag close=" ">4.5.9</tag>simplify-uncertainty + +

+ + + + + + + + + + + + + 10.56 + + + + 0.02 + + + + - + 0.02 + + + + + - 1 234.567 8 + + + 10.56 + + ± + 0.02 + + -

+

- + - 1.4.3 - 1.4.3 - §1.4.3 + 4.5.10 + subsubsection 4.5.10 + 4.5.10 + §4.5.10 - <tag close=" ">1.4.3</tag>output-complex-root,output-decimal-marker,copy-complex-root,copy-decimal-marker - -

+ 4.5.10bracket-ambiguous-numbers + +

- 1.23 + + × + 1 + + + 10 + 10 + + - + - - - - 1 - , - 23 - - + + × + + + + ( + + + 2 + i + + ) + + + + + 10 + 10 + + - + - + - 1 - - - 2 - i + × + + + + + + + + ( + + + + 1 + + + 2 + i + + + ) + + + + + 10 + 10 - + - + - 1 - - - 2 - i + × + + + + 1 + + + 2 + i + + + + + 10 + 10 - + + + - + - 1 - - - 2 - j + × + + + + + + + + ( + + ± + 1.2 + 0.3 + + ) + + + + + 10 + 4 - + - + - 1 - - - 2 - j + × + + ± + 1.2 + 0.3 + + + + 10 + 4 - + + + - - - - 555 - , - 555 - - + + × + + ± + 1.234 + 0.005 + + + + 10 + + - + 4 + + + -

+

- + - 1.4.4 - 1.4.4 - §1.4.4 + 4.5.11 + subsubsection 4.5.11 + 4.5.11 + §4.5.11 - <tag close=" ">1.4.4</tag>complex-root-position - -

+ 4.5.11negative-color + +

- - - 67 - - - 0.9 - i - + - + 15 673 + + + + + + - + 15 673 + + +

+
+ +

also: + + 0 + + + + + - + 0 + + + + + + - + 10 + + + + + + - + 10 + + +

+
+ +

+ + 1 + + + + + - + 1 + + + + + + + 3 + i - + - - - 67 - - - i - 0.9 + - + + + 3 + i - + - - - 67 - - - 0.9 - i + + + 1 + + + 3 + i -

-
-
- - - 1.4.5 - 1.4.5 - §1.4.5 - - <tag close=" ">1.4.5</tag>exponent-base, exponent-product - -

+ - - × - 1 - - - 10 - 2 + + - + + + + 1 + + + 3 + i + - + - - - 1 - - - 10 - 2 + + - + 1 + + + 3 + i - + - × - 1 - - - 2 - 2 + - + + - + 1 + + + 3 + i + -

+

- + - 1.4.6 - 1.4.6 - §1.4.6 + 4.5.12 + subsubsection 4.5.12 + 4.5.12 + §4.5.12 - <tag close=" ">1.4.6</tag>output-exponent-marker - -

+ 4.5.12bracket-negative-numbers + +

- - - 1 - - - e - 2 - + + - + 15 673 - + - - - 1 - - - E - 2 + + + + ( + 15 673 + ) + + + + + + + + + - + 10 + m -

-
-
- - - 1.4.7 - 1.4.7 - §1.4.7 - - <tag close=" ">1.4.7</tag>separate-uncertainty,uncertainty-separator,output-open-uncertainty,output-close-uncertainty - -

+ - - 1.234 - - + + + ( - 5 + 10 ) + m - +

+
+ +

- - 1.234 - - + + + + ( - 5 + 5 ) - + - - ± - 1.234 - 0.005 - + + + + ( + + + 13 + + + + ( + 1 + ) + + + + ) + + - + - - ± - 1.234 - 0.005 - + + + + ( + + + 13 + + + + ( + 1 + ) + + + + ) + + - - + - - - 1.234 - - - - + + + + ( + + + 10 + 10 - - [ - 5 - ] - - - + ) + + - - + - - - 8.2 - - - - ( - 13 - ) - - - + + + + ( + + × + 2 + + + 10 + 10 + + + ) + + - + - - - 8.2 - - - - ( - 13 - ) - - - + 1 + + + + + + + ( + 1 + ) + + - + - ± - 8.2 - 1.3 + + 3 + i - + - ± - 8.2 - 1.3 + - + + + 3 + i + -

-
- -

+ - × - - - 1.234 - - - - ( - 5 - ) - - + + + 1 + + + 3 + i - π - + - × - - - - - + - + + + + 1 + + + 3 + i - - ( - - ± - 1.234 - 0.005 - - ) - - - π + -

-
- -

+ - - 1.200 - - - - ( - 1 - ) - - + - + 1 + + + 3 + i + - + - ± - 1.2 - 0.001 + - + + - + 1 + + + 3 + i + + -

+

- + - 1.4.8 - 1.4.8 - §1.4.8 + 4.5.13 + subsubsection 4.5.13 + 4.5.13 + §4.5.13 - <tag close=" ">1.4.8</tag>bracket-numbers, open-bracket, close-bracket - -

- - - × - 1 - + 4.5.13tight-spacing + +

+ + + × + 2 + 10 - 10 + 3 - + - - × - - - 2 - i - - + + × + 2 + 10 - 10 + 3 - +

+
+
+ + + 4.5.14 + subsubsection 4.5.14 + 4.5.14 + §4.5.14 + + <tag close=" ">4.5.14</tag>print-implicit-plus, print-[exponent|mantissa]-implicit-plus + +

a + + 345 + + - × - - - - - - - - ( - - + - 1 - - - 2 - i - - - ) - - - - - 10 - 10 - + + + 345 - + - × - - + - 1 - - - 2 - i - - - - - 10 - 10 - + + + 345 - - + - - × - - - - - - - - { - - + - 1 - - - 2 - i - - - } - - - + 345 + + b + + + × + 1 + 10 - 10 + 2 -

-
-
- - - 1.4.9 - 1.4.9 - §1.4.9 - - <tag close=" ">1.4.9</tag>negative-color - -

+ - - - - - - 15 673 + + + + + × + 1 + + + 10 + + + + 2 + + - + - + - - - - - - 15 673 + + + + + × + 1 + + + 10 + 2 + - + -

-
-
- - - 1.4.10 - 1.4.10 - §1.4.10 - - <tag close=" ">1.4.10</tag>bracket-negative-numbers - -

+ - - - - - - 15 673 + + × + 1 + + + 10 + + + + 2 + - - - - - - - - ( - 15 673 - ) - - + -

-
-
-
- - - 1.5 - 1.5 - §1.5 - - <tag close=" ">1.5</tag>Multi-part Numbers - - - 1.5.1 - 1.5.1 - §1.5.1 - - <tag close=" ">1.5.1</tag>input-product,input-quotient - -

+ c - - × - - × - 1 - 2 + + × + 1 + + + 10 + 2 - 3 - + - / - - × - - × - - × - 1 - - - 10 - 4 - - - - - 2 - - - - ( - 3 - ) - - + + + + × + 1 + + + 10 + + + + 2 - 3 - 4 - + - × - - × - 4 - 5 + + + + × + 1 + + + 10 + 2 + - 6 - + - - / - 1 - + + × + 1 + + + 10 - - - + + + 2 - - ( - - × - 2 - - - 10 - 4 - - - ) - - + - + d - / - - × - 1 - + - + + × + 1 + 10 2 - - - - - - - - ( - - × - 3 - - - 10 - 4 - - - ) - - -

-
-
- - - 1.5.2 - 1.5.2 - §1.5.2 - - <tag close=" ">1.5.2</tag>output-product, output-quotient - -

+ - - - - 4.87 - 5.321 + - + + × + 1 + + + 10 + + + + 2 + + - 6.905 45 - + - div - 1 - 2 + - + + × + 1 + + + 10 + 2 + + -

-
-
- - - 1.5.3 - 1.5.3 - §1.5.3 - - <tag close=" ">1.5.3</tag>quotient-mode - -

+ - / - 1 - - - - - - - - ( - - × - 2 - - - 10 - 4 - + - + + × + 1 + + + 10 + + + + 2 - ) - - + + - - - - - - 1 - - × - 2 - - - 10 - 4 + + e + + + × + 1 + + + 10 + + - + 2 -

-
-
- - - 1.5.4 - 1.5.4 - §1.5.4 - - <tag close=" ">1.5.4</tag>fraction-function - -

+ - - 1 - 1 + + + + × + 1 + + + 10 + + - + 2 + + + - + - - 1 - 2 + + + + × + 1 + + + 10 + + - + 2 + + + - + - - - 1 - 4 + + × + 1 + + + 10 + + - + 2 + + -

+

-
- - - 1.6 - 1.6 - §1.6 - - <tag close=" ">1.6</tag>Lists and ranges of numbers - + - 1.6.1 - 1.6.1 - §1.6.1 + 4.5.15 + subsubsection 4.5.15 + 4.5.15 + §4.5.15 - <tag close=" ">1.6.1</tag>list-final-separator,list-pair-separator,list-separator - -

- - - - - - - - - - 0.1 - , - 0.2 - and - 0.3 - - - - + 4.5.15print-unity-mantissa, print-zero-[exponent|integer] + +

- - - - - - + + × + 1 + + + 10 + 4 - - 0.1 - , - 0.2 - and - 0.3 - - + - + - - - - - - - - - 0.1 - ; - 0.2 - and - 0.3 - - + + + 10 + 4 + - + - - - - - - - - - 0.1 - , - 0.2 - , - 0.3 - - + 444 - + - - - - - - + + × + 444 + + + 10 + 0 - - 0.1 - and - 0.2 - and finally - 0.3 - - + - + - - - - - - - - 0.1 - and - 0.2 - - + 0.123 - + - - - - - - - - 0.1 - , and - 0.2 - - + .123 -

+

-
-
- - - 1.7 - 1.7 - §1.7 - - <tag close=" ">1.7</tag>range-phrase - -

- - - - - - - - - 5 - to - 100 - - - - - - - - - - - - - 5 - - 100 - - - - - - - - - - - - - 5 - - 100 - - - -

-
-
- - - 1.8 - 1.8 - §1.8 - - <tag close=" ">1.8</tag>Angles - - - 1.8.1 - 1.8.1 - §1.8.1 - - <tag close=" ">1.8.1</tag>number-angle-product - -

+ +

- - - - - 2.67 - ° - - + + + 10 + 4 + - + - - - - - 2.67 - ° - - + + + 10 + 4 +

-
- - - 1.8.2 - 1.8.2 - §1.8.2 - - <tag close=" ">1.8.2</tag>arc-separator - -

+ +

- - - - - - - 6 - ° - - - - 7 - - - - - 6.5 - - - - + 1 - + - - - - - - - 6 - ° - - - - 7 - - - - - 6.5 - - + 1 + + + + + × + 1 + + + 10 + 0 - + + + + + + + 10 + 0 +

- + - 1.8.3 - 1.8.3 - §1.8.3 + 4.5.16 + subsubsection 4.5.16 + 4.5.16 + §4.5.16 - <tag close=" ">1.8.3</tag>add-arc-degree-zero,add-arc-minute-zero,add-arc-second-zero - -

- - - - - - - - - 1 - ° - - - + 4.5.16zero-decimal-as-symbol, zero-symbol + +

+ + 123.00 - + + + - - - - - - - 2 - - - + + + 123 + . + + - + - + - - - - - 3 - - + + 123 + - - - + - - - - - - - 1 - ° - - + + + 123 + . + [—] + - +

+
+
+
+ + + 4.6 + subsection 4.6 + 4.6 + §4.6 + + <tag close=" ">4.6</tag>Lists, products and ranges + + + 4.6.1 + subsubsection 4.6.1 + 4.6.1 + §4.6.1 + + <tag close=" ">4.6.1</tag>list-[final|pair]-separator, list-separator + +

- - - - - - - - 0 - ° - - - - 2 - - - + + + + + + 0.1 + , + 0.2 + and + 0.3 + - + - - - - - - - - 0 - ° - - - - 3 - - - + + + + + + 0.1 + ; + 0.2 + and + 0.3 + - - - - + - - - - - - - - 1 - ° - - - - 0 - - - + + + + + + 0.1 + , + 0.2 + , + 0.3 + - + - - - - - - 2 - - + + + + + + 0.1 + and + 0.2 + and finally + 0.3 + - + - - - - - - - - 0 - - - - - 3 - - - + + + + + 0.1 + and + 0.2 + - - - - + - - - - - - - - 1 - ° - - - - 0 - - - + + + + + 0.1 + , and + 0.2 + - + - - - - - - - - - 2 - - - - - 0 - - - + + + + + + + 0.1 + , + 0.2 + and + 0.3 + - +

+
+
+ + + 4.6.2 + subsubsection 4.6.2 + 4.6.2 + §4.6.2 + + <tag close=" ">4.6.2</tag>product-[mode|phrase|symbol] + +

- - - - - - - - 3 - - + + × + + × + 5 + 100 - + 2 + - - + - - - - - 45.697 - ° + + + + + 5 + 100 - + 2 + - + + - - - - - 45.697 - ° + + by + + by + 5 + 100 - + 2 + + + + + + BY + + BY + 5 + 100 + + 2 + -

+

- + - 1.8.4 - 1.8.4 - §1.8.4 + 4.6.3 + subsubsection 4.6.3 + 4.6.3 + §4.6.3 - <tag close=" ">1.8.4</tag>angle-symbol-over-decimal - -

+ 4.6.3range-open-phrase, range-phrase + +

- - - 45.697 - ° + + + + + 5 + to + 100 + - - - - - - - - - 6 - ° - - - - 7 - - - - - 6.5 - - + + + + + + + + + 5 + + 100 + - + - - - 45 - . - ° - 697 + + + + + 10 + to + 12 + - + - - - - - 6 - ° - - - - 7 - - - - - 6 - . - - 5 - + + + + + from + 5 + to + 100 + - + - - - - - 6 - ° - - - - 7 - - - - - 6 - . - - 5 - + + + + + 5 + + 100 +

-
-
-
- - 2 - 2 - §2 - - <tag close=" ">2</tag>Units - - - Table 1 - 1 - Table 1 - - 1SI base units - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 1SI base units
UnitMacroSymbol
ampere\ampere - - A - -
candela\candela - - cd - -
kelvin\kelvin - - K - -
kilogram\kilogram - - kg - -
metre\metre - - m - -
mole\mole - - mol - -
second\second - - s - -
- - - Table 2 - 2 - Table 2 - - 2Coherent derived units - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 2Coherent derived units
UnitMacroSymbolUnitMacroSymbol
becquerel\becquerel - - Bq - - newton\newton - - N - -
degreeCelsius\degreeCelsius - - °C - - ohm\ohm - - - -
coulomb\coulomb - - C - - pascal\pascal - - Pa - -
farad\farad - - F - - radian\radian - - rad - -
gray\gray - - Gy - - siemens\siemens - - S - -
hertz\hertz - - Hz - - sievert\sievert - - Sv - -
henry\henry - - H - - steradian\steradian - - sr - -
joule\joule - - J - - tesla\tesla - - T - -
katal\katal - - kat - - volt\volt - - V - -
lumen\lumen - - lm - - watt\watt - - W - -
lux\lux - - lx - - weber\weber - - Wb - -
- - - Table 3 - 3 - Table 3 - - 3Non-SI units - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 3Non-SI units
UnitMacroSymbol
day\day - - d - -
degree\degree - - ° - -
hectare\hectare - - ha - -
hour\hour - - h - -
litre\litre - - l - -
liter\liter - - L - -
arcminute\arcminute - - - -
minute\minute - - min - -
arcsecond\arcsecond - - - -
tonne\tonne - - t - -
- - - Table 4 - 4 - Table 4 - - 4Expermental Non-SI units - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 4Expermental Non-SI units
UnitMacroSymbol
astronomicalunit\astronomicalunit - - ua - -
atomicmassunit\atomicmassunit - - u - -
bohr\bohr - - - - - - a - 0 - - - - -
clight\clight - - - - - - c - 0 - - - - -
dalton\dalton - - Da - -
electronmass\electronmass - - - - - - m - e - - - - -
electronvolt\electronvolt - - eV - -
elementarycharge\elementarycharge - - - - e - - - -
hartree\hartree - - - - - - E - h - - - - -
planckbar\planckbar - - - - - - - -
- - - Table 5 - 5 - Table 5 - - 5Other non-SI units - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 5Other non-SI units
UnitMacroSymbol
angstrom\angstrom - - Å - -
bar\bar - - bar - -
barn\barn - - b - -
bel\bel - - B - -
decibel\decibel - - dB - -
knot\knot - - kn - -
mmHg\mmHg - - mmHg - -
nauticalmile\nauticalmile - - M - -
neper\neper - - Np - -
- - - Table 6 - 6 - Table 6 - - 6Other non-SI units - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 6Other non-SI units
UnitMacroSymbolPowerUnitMacroSymbolPower
yocto\yocto - - y - - - + + + 4.6.4 + subsubsection 4.6.4 + 4.6.4 + §4.6.4 + + 4.6.4[list|product|range]-exponents + +

+ + - - - - 10 - -24 + + + + + + + + + × + 5 + + + 10 + 3 + + + , + + × + 7 + + + 10 + 3 + + + , + + × + 9 + + + 10 + 3 + + + and + + × + 1 + + + 10 + 4 + + + + + + + + + × + + × + + × + + × + 5 + + + 10 + 3 + + + + × + 7 + + + 10 + 3 + + - - - -

deca\deca - - da - - - - - - - - 10 - 1 + + × + 9 + + + 10 + 3 + - - -
zepto\zepto - - z - - - - - - + + × + 1 + - 10 - -21 + 10 + 4 - - - hecto\hecto - - h - - - + + + + + - - - - 10 - 2 - - + + + - -
atto\atto - - a - - - - - - - - 10 - -18 + + + × + 5 + + + 10 + 3 + + + to + + × + 7 + + + 10 + 3 + + + + + + + + + + + × + + + + + + + - + + ( + 5 + , + 7 + , + 9 + and + 10 + ) + + + + + 10 + 3 - - kilo\kilo - - k - - - - - - - - 10 - 3 + + + + + + × + + + + ( + + × + + × + + × + 5 + 7 + + 9 + + 10 + + ) + + + + + 10 + 3 + + + + + + + × + + + + + - + + ( + 5 + to + 7 + ) + + + + + 10 + 3 - -
femto\femto - - f - - - - - - - - 10 - -15 + + + + + + × + + + + + - + + from + + ( + 5 + to + 7 + ) + + + + + + 10 + 3 - - mega\mega - - M - - - - - - - - 10 - 6 + + + + + + + × + + + + + + + - + + 5 + , + 7 + , + 9 + and + 10 + + + + + 10 + 3 - -
pico\pico - - p - - - - - - - - 10 - -12 + + + + + + × + + × + + × + + × + 5 + 7 + + 9 - + 10 - - giga\giga - - G - - - - - - - - 10 - 9 + + + 10 + 3 + + + + + + + × + + + + + - + + 5 + to + 7 + + + + + 10 + 3 - -
nano\nano - - n - - - + + +

+ + + + + 4.6.5 + subsubsection 4.6.5 + 4.6.5 + §4.6.5 + + <tag close=" ">4.6.5</tag>[list|product|range]-units + +

+ + - - - - 10 - -9 - - + + + + + - -

tera\tera - - T - - - + + + + 2 + T + + , + + + 4 + T + + , + + + 6 + T + + and + + + 8 + T + + + + + + + + + + + + + + + + + + ( + 2 + , + 4 + , + 6 + and + 8 + ) + + + T + + + + + - - - - 10 - 12 + + + + + + + + + + 2 + T + + , + + + 4 + T + + , + + + 6 + T + + and + + + 8 + T + + + + + + + + + + + + + + + - - - -
micro\micro - - µ - - - + + 2 + , + 4 + , + 6 + and + 8 + + + T + + + + + - - - - 10 - -6 - - + + + - - peta\peta - - P - - - - - - - - 10 - 15 + + + + 2 + °C - - - -
milli\milli - - m - - - - - - - - 10 - -3 + to + + + 4 + °C - - - - exa\exa - - E - - - - - - - - 10 - 18 + + + + + + + + + + + + - - - -
centi\centi - - c - - - + + ( + 2 + to + 4 + ) + + + °C + + + + + - - - - 10 - -2 - - + + + - - zetta\zetta - - Z - - - - - - - - 10 - 21 + + + + 2 + °C - - - -
deci\deci - - d - - - - - - - - 10 - -1 + to + + + 4 + °C - - - - yotta\yotta - - Y - - - - - - - - 10 - 24 + + + + + + + + + + + + - - - -
- - - Table 7 - 7 - Table 7 - - 7Abbreviated units - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 7Abbreviated units
UnitMacroSymbol
fg\fg - - fg - -
pg\pg - - pg - -
ng\ng - - ng - -
ug\ug - - - - µ - g - - -
mg\mg - - mg - -
g\g - - g - -
kg\kg - - kg - -
amu\amu - - u - -
pm\pm - - pm - -
nm\nm - - nm - -
um\um - - - - µ - m - - -
mm\mm - - mm - -
cm\cm - - cm - -
dm\dm - - dm - -
m\m - - m - -
km\km - - km - -
as\as - - as - -
fs\fs - - fs - -
ps\ps - - ps - -
ns\ns - - ns - -
us\us - - - - µ - s - - -
ms\ms - - ms - -
s\s - - s - -
fmol\fmol - - fmol - -
pmol\pmol - - pmol - -
nmol\nmol - - nmol - -
umol\umol - - - - µ - mol - - -
mmol\mmol - - mmol - -
mol\mol - - mol - -
kmol\kmol - - kmol - -
pA\pA - - pA - -
nA\nA - - nA - -
uA\uA - - - - µ - A + + 2 + to + 4 + + + °C + + + + + + × + + + 2 + m - -
mA\mA - - mA - -
A\A - - A - -
kA\kA - - kA - -
ul\ul - - - - µ - l + + + 3 + m - -
ml\ml - - ml - -
l\l - - l - -
hl\hl - - hl - -
uL\uL - - - - µ - L + + + 4 + m - -
mL\mL - - mL - -
L\L - - L - -
hL\hL - - hL - -
mHz\mHz - - mHz - -
Hz\Hz - - Hz - -
kHz\kHz - - kHz - -
MHz\MHz - - MHz - -
GHz\GHz - - GHz - -
THz\THz - - THz - -
mN\mN - - mN - -
N\N - - N - -
kN\kN - - kN - -
MN\MN - - MN - -
Pa\Pa - - Pa - -
kPa\kPa - - kPa - -
MPa\MPa - - MPa - -
GPa\GPa - - GPa - -
mohm\mohm - - - - m - + + + + + + + + + + ( + + × + 2 + 3 + 4 + + ) + + + m + + + + + + × + + + 2 + m - -
kohm\kohm - - - - k - + + + 3 + m - -
Mohm\Mohm - - - - M - + + + 4 + m - -
pV\pV - - pV - -
nV\nV - - nV - -
uV\uV - - - - µ - V + + + + + + + + × + 2 + 3 + 4 - -
mV\mV - - mV - -
V\V - - V - -
kV\kV - - kV - -
W\W - - W - -
uW\uW - - - - µ - W + m + + + + + + + + + + ( + + × + 2 + 3 + 4 + + ) + + + + + m + 3 - -
mW\mW - - mW - -
kW\kW - - kW - -
MW\MW - - MW - -
GW\GW - - GW - -
J\J - - J - -
kJ\kJ - - kJ - -
eV\eV - - eV - -
meV\meV - - meV - -
keV\keV - - keV - -
MeV\MeV - - MeV - -
GeV\GeV - - GeV - -
TeV\TeV - - TeV - -
kWh\kWh - + + + + + + + + × + 2 + 3 + 4 + + + + m + 3 + + + +

+ + + + + 4.6.6 + subsubsection 4.6.6 + 4.6.6 + §4.6.6 + + <tag close=" ">4.6.6</tag>[list|product|range]-[close|open]-bracket + +

+ + + + + + + + + + + + + [ + + × + 5 + + + 10 + 3 + + + , + + × + 7 + + + 10 + 3 + + + , + + × + 9 + + + 10 + 3 + + + and + + × + 1 + + + 10 + 4 + + + ] + + + s + + + + + + + + + + + + + + { + + × + + × + 5 + + + 10 + 3 + + + + × + 7 + + + 10 + 3 + + + + × + 9 + + + 10 + 3 + + + + × + 1 + + + 10 + 4 + + + + } + + + m + + + + + + + + + + + + + + + + 2 + to + 4 + + + + °C + + + + + + - - kW - h + + + + + - -

F\F - - F - -
fF\fF - - fF - -
pF\pF - - pF - -
K\K - - K - -
dB\dB - - dB - -
- - - Table 8 - 8 - Table 8 - - 8Binary prefixes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 8Binary prefixes
UnitMacroSymbolPower
kibi\kibi - - Ki - - - + + + × + 5 + + + 10 + 3 + + + , + + × + 7 + + + 10 + 3 + + + , + + × + 9 + + + 10 + 3 + + + and + + × + 1 + + + 10 + 4 + + + + + + + + + + × + + × + + × + + × + 5 + + + 10 + 3 + + + + × + 7 + + + 10 + 3 + + + + + × + 9 + + + 10 + 3 + + + + + × + 1 + + + 10 + 4 + + + + + + + + + + + + + + + + + ( + 2 + to + 4 + ) + + + °C + + +

+ + + + + 4.6.7 + subsubsection 4.6.7 + 4.6.7 + §4.6.7 + + <tag close=" ">4.6.7</tag>[list|product|range]-independent-prefix + +

a + + + + + + + + + + + + × + 1 + + + 10 + 3 + + + W + + to + + + + × + 1 + + + 10 + 9 + + + W + + + + + + + - - - - 2 - 10 + + + + + + + + + × + 1 + + + 10 + 3 + + + W + + and + + + + × + 1 + + + 10 + 9 + + + W + + + + + + + + × + + + + × + 1 + + + 10 + 3 + - + W - -

mebi\mebi - - Mi - - - - - - - - 2 - 20 + + + + × + 1 + + + 10 + 9 + - + W - -
gibi\gibi - - Gi - - - + + + b + + - - - - 2 - 30 - - + + + - -
tebi\tebi - - Ti - - - + + + + + × + 1 + + + 10 + 3 + + + W + + to + + + + × + 1 + + + 10 + 9 + + + W + + + + + + + - - - - 2 - 40 + + + + + + + + + × + 1 + + + 10 + 3 + + + W + + and + + + + × + 1 + + + 10 + 9 + + + W + + + + + + + + × + + + + × + 1 + + + 10 + 3 + - + W - -
pebi\pebi - - Pi - - - - - - - - 2 - 50 + + + + × + 1 + + + 10 + 9 + - + W - -
exbi\exbi - - Ei - - - + + + c + + - - - - 2 - 60 - - + + + - -
zebi\zebi - - Zi - - - + + + + 1000 + W + + to + + + 1 000 000 000 + W + + + + + + + - - - - 2 - 70 + + + + + + + + 1 + kW + + to + + + 1 000 000 + kW - + + + + + + + + + + - -
yobi\yobi - - Yi - - - + + + + 1000 + W + + and + + + 1 000 000 000 + W + + + + + + + - - - - 2 - 80 + + + + + + + + 1 + kW + + and + + + 1 000 000 + kW - + + + + + + + × + + + 1000 + W - -
- - - 2.1 - 2.1 - §2.1 - - <tag close=" ">2.1</tag>Using units - -

- - kg - - - - - kg - - - - - - - km - - - - - - - - kg - -

-
- -

- - a - - - - a - - - - a - - - - e - - - - e - -

-
- -

- - a - - - - a - -

-
- -

- - km - -

-
- -

- - - - kg - m - - - s - - - - 1 + + + 1 000 000 000 + W - - - - - - - kg - m - - - s + + + + + × + + + 1 + kW + + + + 1 000 000 + kW + + + + d + + - - - 1 + + + + + + + + 1 + kW + + to + + + 1 + GW + + + + + + + + + + + + + + + + 1 + kW + + and + + + 1 + GW + + + + + + + + × + + + 1 + kW + + + + 1 + GW - - - - - - - kg - m - - - s - - - - 1 + +

+
+ + + + 4.6.8 + subsubsection 4.6.8 + 4.6.8 + §4.6.8 + + <tag close=" ">4.6.8</tag>prefix-mode = combine-exponent + +

+ + + + 1700 + g + + + + + + + + × + 1.7 + + + 10 + 3 + + g - - - - - - - kg - m - - - s - - - - 1 + + + + + + + 1700 + g + + + + + + + 1.7 + kg + + + + + + + + + + × + 1.700 + + + 10 + 3 + + g - - - - - - - kg - m - - - s - - - - 1 + + + + + + + × + 1.7 + + + 10 + 3 + + g - - -

-
- -

- - - - - - kg + +

+
+
+
+ + + 4.7 + subsection 4.7 + 4.7 + §4.7 + + <tag close=" ">4.7</tag>Complex Numbers + + + 4.7.1 + subsubsection 4.7.1 + 4.7.1 + §4.7.1 + + <tag close=" ">4.7.1</tag>complex-mode + +

+ + + + + 1 + + + + i + - m - - - s + + + + - - - 1 + + + - - - - - - - - kg - - - m - - - - s - - - 1 + + 1 + + + + 45 + ° + + + + + + + + + + 1 + + + + i - - - - - - - kg - - - m + + + + + + + 0.71 + + + 0.71 + i + - - - s + + + + - - - 1 + + + - - - - - - - - kg - m - - - - s - - - - 1 + + 1.414 213 562 373 1 + + + + 45 + ° - - - - - - - - kg - m - - + + + + + - - s - - - - 1 + + + + + + + 1 + + + + 45 + ° - - - -

-
- + + +

+ +
+ - 2.1.1 - 2.1.1 - §2.1.1 + 4.7.2 + subsubsection 4.7.2 + 4.7.2 + §4.7.2 - <tag close=" ">2.1.1</tag>forbid-literal-units, inter-unit-product - -

+ 4.7.2input-complex-roots + +

- - - - F - 2 + + + 9.99 + + + 88.8 + i - lm - cd - + - - - - F - 2 - - lm - cd - - - - - - - - - F - 2 + + + 9.99 + + + 88.8 + i - lm - cd -

+

- + - 2.1.2 - 2.1.2 - §2.1.2 + 4.7.3 + subsubsection 4.7.3 + 4.7.3 + §4.7.3 - <tag close=" ">2.1.2</tag>per-mode, per-symbol, bracket-unit-denominator - -

+ 4.7.3output-complex-root + +

- - J - - - mol - - - - 1 - - - - - K - - - - 1 - + + + 1 + + + 2 + i - + - - m - - - s - - - - 2 - + + + 1 + + + 2 + i - + - - J - - - mol - K + + + 1 + + + 2 + i - + - - - - J - - - mol - - - - 1 - - + + + 1 + + + 2 + j - K - +

+
+
+ + + 4.7.4 + subsubsection 4.7.4 + 4.7.4 + §4.7.4 + + <tag close=" ">4.7.4</tag>complex-root-position + +

- - m - - - s - 2 + - + 67 + + + 0.9 + i - + - - A - - - mol - - - - 1 - + - + 67 + + + i + 0.9 - s - + - - A - s - - - mol - - - - 1 - + - + 67 + + + 0.9 + i

- -

+ + + + 4.7.5 + subsubsection 4.7.5 + 4.7.5 + §4.7.5 + + 4.7.5complex-angle-unit, complex-symbol-angle, complex-symbol-degree + +

- / - J - + + - - - + + + - - ( - - - mol - K + + + 1 + + + + 1 + ° - ) - + + + + + + + + + + + + + + + + + + 1 + + 1 + + - + - / - m - - - s - 2 - - - - - - -  div  - J - + + - - - + + + - - ( - - - mol - K + + + 1 + + + + 1 + d - ) - + + - +

+
+
+ + + 4.7.6 + subsubsection 4.7.6 + 4.7.6 + §4.7.6 + + <tag close=" ">4.7.6</tag>print-complex-unity + +

- / - J - - - mol - K + + + + + i + - - + - / - - / - J - mol + + + + 1 + i - K + - - + - / - J - - - - - - - - ( - - - mol - K - - ) - - + + + + 1 + i + +

- - +
+
+ + + 4.7.7 + subsubsection 4.7.7 + 4.7.7 + §4.7.7 + + <tag close=" ">4.7.7</tag>Other tests + +

Real numbers as complex: + + 1 + + + + 1 + + - - J - - - mol - K - + - + 1 - - -

+ + + 1 + + - / - J - - - - - - - - ( - - - mol - K - - ) - - + - + 1 - + + + 1 + + - - J - - - mol - K + - + + - + 1 + + + + + × + 2.068 231 071 102 14 + + + 10 + + - + 13 + + + + i -

- - + - / - J - - - - - - - - ( - - - mol - K + + + 1 + + + + × + 4.136 462 142 204 29 + + + 10 + + - + 13 + - ) - - + + i + - - - - +

+
+ +

- - / - J - - - - - - - - ( - - - mol - K - - ) - - - + + + + + + + + + 1 + + 1.570 796 326 794 9 + + - - +

- +
+ + + 4.8 + subsection 4.8 + 4.8 + §4.8 + + <tag close=" ">4.8</tag>Angles + - 2.1.3 - 2.1.3 - §2.1.3 + 4.8.1 + subsubsection 4.8.1 + 4.8.1 + §4.8.1 - <tag close=" ">2.1.3</tag>sticky-per - -

+ 4.8.1angle-mode + +

- - - Pa - - - Gy - - - - 1 - + + + + + 2.67 + ° - H - + - + - - - Pa - - - Gy + + + + - - - 1 + + 2 + ° - - - - H - - - 1 + + 3 + + + + + 4 + - + -

-
-
- - - 2.1.4 - 2.1.4 - §2.1.4 - - <tag close=" ">2.1.4</tag>power-font - -

+ - - - m - - - s + + + + - - - 2 + + 2 + ° + + + + 40 + + + + + 12 + - + - + - - - m - - - s + + + + - - - 2 + + 2 + ° + + + + 3 + + + + + 4 + - + -

-
-
- - - 2.1.5 - 2.1.5 - §2.1.5 - - <tag close=" ">2.1.5</tag>literal-superscript-as-power - -

+ - - - m + + - - s - 2 + + 2.67 + ° - + - + - - - m + + - - s - 2 + + 2.051 111 111 111 111 1 + ° - + -

+

- + - 2.1.6 - 2.1.6 - §2.1.6 + 4.8.2 + subsubsection 4.8.2 + 4.8.2 + §4.8.2 - <tag close=" ">2.1.6</tag>qualifier-mode, qualifier-phrase - -

+ 4.8.2angle-separator + +

- - - - - - - kg - pol - - 2 - - - - - - mol - cat + + + + + + + 6 + ° - - - 1 + + 7 + - - - - h - - - 1 + + 6.5 + - + - + - - - - - + + + + + - kg - - - - ( - pol - ) - - + 6 + ° - 2 - - - - + - mol - - - - ( - cat - ) - - + 7 + - - - 1 + + 6.5 + - - - h + + +

+
+
+ + + 4.8.3 + subsubsection 4.8.3 + 4.8.3 + §4.8.3 + + <tag close=" ">4.8.3</tag>fill-angle-[degrees|minutes|seconds] + +

+ + + + + - - - - 1 + + 1 + ° - + - + - - - - - - - kg - pol - - 2 - - - - - - mol - cat - + + + + - - - - 1 + + 2 + - - - h + + + + + + + + - - - - 1 + + 3 + - + - + + + - - - - - - - - ( - - - kg - pol - - ) - - - 2 - - - - - - - ( - - - mol - cat - - ) - - + + + + - - - - 1 + + 1 + ° - - - h + + + + + + + + - - - - 1 + + + + 0 + ° + + + + 2 + + - - - - - dBi + -

-
- -

+ - - - - - - - - ( - - - kg - of - pol - - ) - - - 2 - - - - - - - ( - - - mol - of - cat - - ) - - + + + + - - - - 1 + + + + 0 + ° + + + + 3 + + - - - h + + + + + + + + + + + - - - - 1 + + + + 1 + ° + + + + 0 + + - + - + - - - - - - - - ( - kgbypol - ) - - - 2 - - - - - - - ( - molbycat - ) - - + + + + - - - - 1 + + 2 + - - - h + + + + + + + + - - - - 1 + + + + 0 + + + + + 3 + + - + -

-
-
- - - 2.1.7 - 2.1.7 - §2.1.7 - - <tag close=" ">2.1.7</tag>prefixes-as-symbols - -

+ + + + - - - ml - - - mol + + + + - - - - 1 + + + + 1 + ° + + + + 0 + + - dA - + - + - - - - - 10 - -4 - - - - l - - - mol + + + + - + + - - - 1 + + 2 + + + + + 0 + - A - + - + - - - - - 10 - -1 - - - - - - kg - 2 + + + + - + + + 3 + - s - + - + + - - - - - Mg - 2 + + + + + 45.697 + ° - ds - + - + - - - - - 10 - 5 + + + + + 45.697 + ° - - - - - kg - 2 + + +

+
+
+ + + 4.8.4 + subsubsection 4.8.4 + 4.8.4 + §4.8.4 + + <tag close=" ">4.8.4</tag>angle-symbol-[degree|minute|second] + +

+ + + + + + + + 6 + ° + + + + 7 + + + + + 6.5 + - s - + - + + - - - - - + + + + + - µ - g + 6 + d + + + + 7 + m + + + + 6.5 + s - 2 - ds - + - +

+
+
+ + + 4.8.5 + subsubsection 4.8.5 + 4.8.5 + §4.8.5 + + <tag close=" ">4.8.5</tag>angle-symbol-over-decimal + +

- - - - - 10 - -19 - - - - - - kg - 2 - - s + + + + + 45.697 + ° - + - + - - - - - Mg + + + + - - - 2 + + 6 + ° + + + + 7 + + + + + 6.5 + - ds - + - + - - - - - 10 - -7 - - - - - - kg - - - - 2 - - - s + + + + + 45 + . + ° + 697 - + - + - - - - - + + + + + - µ - g + 6 + ° - - - 2 + + 7 + + + + + 6 + . + + 5 - ds - + - + - - - - - 10 - 17 - - - - - - kg - - - - 2 - + + + + + + + 6 + ° + + + + 7 + + + + + 6 + . + + 5 - s - + -

+

- - - 2.1.8 - 2.1.8 - §2.1.8 - - <tag close=" ">2.1.8</tag>parse-units -
- + - 2.2 - 2.2 - §2.2 + 4.10 + subsection 4.10 + 4.10 + §4.10 - <tag close=" ">2.2</tag>Numbers with units - - - 2.2.1 - 2.2.1 - §2.2.1 - - <tag close=" ">2.2.1</tag>allow-number-unit-breaks - - + <tag close=" ">4.10</tag>Using Units + - 2.2.2 - 2.2.2 - §2.2.2 + 4.10.1 + subsubsection 4.10.1 + 4.10.1 + §4.10.1 - <tag close=" ">2.2.2</tag>number-unit-product - -

- - - - 2.67 - F - - - - - - - 2.67 - F - - - + 4.10.1inter-unit-product + +

- - 2.67 - F - - - - - - - 2.67 - F - - - - - - - 2.67 - F + + + + F + 2 + + lm + cd - + - × - 2.67 - F + + + + F + 2 + + lm + cd - + - × - 2.67 - F + + + + F + 2 + + lm + cd -

+

- + - 2.2.3 - 2.2.3 - §2.2.3 + 4.10.2 + subsubsection 4.10.2 + 4.10.2 + §4.10.2 - <tag close=" ">2.2.3</tag>multi-part-units - -

+ 4.10.2per-mode, [display|inline]-per-mode, per-symbol, fraction-command, bracket-unit-denominator + +

- - - ± - 12.3 - 0.4 + + J + + + mol + + - + 1 + - kg - - - - - - - - ± - 12.3 - 0.4 + + + K + + - + 1 + - kg - + - - - ± - 12.3 - 0.4 + + m + + + s + + - + 2 + - kg - + - - - ± - 12.3 - 0.4 + + J + + + mol + K - kg -

-
- -

+ - × - - ± - 1.234 - 0.005 - - - - 10 - - + + + + J + + + mol - - - 4 + - + 1 - + + K - + - - - × - - ± - 1.234 - 0.005 - - - - 10 - - - - - - 4 - - - + + m + + + s + 2 - m -

-
-
- - - 2.2.4 - 2.2.4 - §2.2.4 - - <tag close=" ">2.2.4</tag>product-units - -

+ - - - × - - × - 2 - 3 + + A + + + mol + + - + 1 - 4 - m + s - + - - - × - - × - 2 - 3 + + A + s + + + mol + + - + 1 - 4 - m - +

+
+ +

- - - × - - × - 2 - 3 + / + J + + + + + - 4 - - m + + ( + + + mol + K + + ) + + - + - - - × - - × - 2 - 3 - - 4 + / + m + + + s + 2 - m - + - - - × - - × - 2 - 3 + div + J + + + + + - 4 - - m + + ( + + + mol + K + + ) + + - + - - - × - - × - 2 - 3 - - 4 + / + J + + + mol + K - m -

-
-
- - - 2.2.5 - 2.2.5 - §2.2.5 - - <tag close=" ">2.2.5</tag>list-units,range-units - -

+ + - - - - - - - + + / + + / + J + mol - - - - 2 - T - - , - - - 4 - T - - , - - - 6 - T - - and - - - 8 - T - - - + K + - +

+
+ +

- - + + 10 + + + m - - - - - + - + 1 - - ( - 2 - , - 4 - , - 6 - and - 8 - ) - - - T + - + - - - - - - - + + + 20 + + / + m + s - - - - 2 - T - - , - - - 4 - T - - , - - - 6 - T + + + + + + + 30 + + + J + + + mol + + - + 1 + - and - - - 8 - T + + + K + + - + 1 + - - + + - +

+
+ +

- - + / + J + - - - - - + + + - 2 - , - 4 - , - 6 - and - 8 + ( + + + mol + K + + ) - T - +

+ + - - - - - - - - - - 2 - °C - - to - - - 4 - °C - - - + + + J + + + mol + K + + - + + +

- - + / + J + - - - + + + ( - 2 - to - 4 + + + mol + K + ) - °C - + - + + + J - - - + + mol + K - - - - 2 - °C - - to - - - 4 - °C - - - + - +

+ + - - + / + J + - - - + + + - 2 - to - 4 + ( + + + mol + K + + ) - °C -

-
-
- - - 2.2.6 - 2.2.6 - §2.2.6 - - <tag close=" ">2.2.6</tag>exponent-to-prefix - -

+ + + + - - - 1700 - g + + / + J + + + + + + + + ( + + + mol + K + + ) + + - + + + + +

Other tests: - - - × - 1.7 - - - 10 - 3 - + / + + + m + L - g + s - - + - - 1700 - g + + J + over + + + mol + K + - +

+
+
+ + + 4.10.3 + subsubsection 4.10.3 + 4.10.3 + §4.10.3 + + <tag close=" ">4.10.3</tag>per-symbol-script-correction + +

- - - × - 1.7 - - - 10 - 3 - + / + + + cm + 3 - g + g - - - + - - 1700 - g + / + + + cm + 3 + + g - +

+
+
+ + + 4.10.4 + subsubsection 4.10.4 + 4.10.4 + §4.10.4 + + <tag close=" ">4.10.4</tag>sticky-per + +

- - - × - 1.7 - - - 10 - 3 + + Pa + + + Gy + + - + 1 - g + H -

-
-
-
-
-
- - 3 - 3 - §3 - - <tag close=" ">3</tag>Tabular material - - - Table 9 - 9 - Table 9 - - 9Standard behaviour of the S column type. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 9Standard behaviour of the S column type.
Some Values
- - 2.3456 - -
- - 34.2345 - -
- - - + + + + + Pa + + + Gy - - - 6.7835 + - + 1 - - -
- - 90.473 - -
- - 5642.5 - -
- - - × - 1.2 - - - 10 - 3 + + + + H + + - + 1 - -
- - - - - - - 10 - 4 + + +

+ + + + + 4.10.5 + subsubsection 4.10.5 + 4.10.5 + §4.10.5 + + <tag close=" ">4.10.5</tag>qualifier-[mode|phrase] + +

+ + + + + + + + kg + pol + 2 - -

- - - Table 10 - 10 - Table 10 - - 10Detection of surrounding material in an S column. - - - - - - - - - - - - - - - - - - - -
Table 10Detection of surrounding material in an S column.
Some Values
- - 12.34 - -
- - 975.31 - -
- - 44.268 - - a
- - - Table 11 - 11 - Table 11 - - 11Controlling complex alignment with the tablenum macro. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 11Controlling complex alignment with the tablenum macro.
HeadingHeading
InfoMore info
InfoMore info
- - 12.34 - -
- - 333.5567 - -
- - 4563.21 - -
HeadingHeading
- - 88.999 - - aaa
bbb
- - 33.435 - - ccc
ddd
- - - Table 12 - 12 - Table 12 - - 12Units in tables. - - - - - - - - - - - - - - - - - - - -
Table 12Units in tables.
Unit
- - - - - - m - 2 + + + + + mol + cat - - - s - - - - 1 - + + - + 1 - -
- - Pa - -
- - + + + h - - - + - + 1 - - m - . - - - s - - - - 1 - - - - - -
- - - Table 13 - 13 - Table 13 - - 13The s column processes everything. - - - - - - - - - - - - - - - - - - - -
Table 13The s column processes everything.
UnitUnit
- - - - m - 3 - - - - - - - m - 3 - -
- - kg - - - - kg - -
- - - 3.0.1 - 3.0.1 - §3.0.1 - - <tag close=" ">3.0.1</tag>table-parse-only - - - Table 14 - 14 - Table 14 - - 14Parsing without aligning in an S column. - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 14Parsing without aligning in an S column.
Decimal-centredSimple centring
- - 12.345 - - - - 12.345 - -
- - 6.78 - - - - 6.78 - -
- - - - - - - - - 88.8 - - - - + + + + + + + + + + + kg + + ( - 9 + pol ) - - - - - - - - - - - 88.8 - - - - + 2 + + + + + + mol + + ( - 9 + cat ) - -
- - - × - 4.5 - - - 10 - 3 - + + - + 1 - - - - - × - 4.5 - - - 10 - 3 - + + + + h + + - + 1 + + + + + + + + + + + + + kg + pol + + 2 + + + + + + mol + cat - -
-
- - - 3.0.2 - 3.0.2 - §3.0.2 - - <tag close=" ">3.0.2</tag>table-number-alignment - - - Table 15 - 15 - Table 15 - - 15Aligning the S column. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 15Aligning the S column.
Some ValuesSome ValuesSome ValuesSome Values
- - 2.3456 - - - - 2.3456 - - - - 2.3456 - - - - 2.3456 - -
- - 34.2345 - - - - 34.2345 - - - - 34.2345 - - - - 34.2345 - -
- - 56.7835 - - - - 56.7835 - - - - 56.7835 - - - - 56.7835 - -
- - 90.473 - - - - 90.473 - - - - 90.473 - - - - 90.473 - -
-
- - - 3.0.3 - 3.0.3 - §3.0.3 - - <tag close=" ">3.0.3</tag>table-figures-decimal, table-figures-exponent,table-figures-integer,table-figures- -uncertainty - - - Table 16 - 16 - Table 16 - - 16Reserving space in S columns. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 16Reserving space in S columns.
ValuesValuesValuesValuesValuesValues
- - 2.3 - - - - 2.3 - - - - - 2.3 - - - - ( - 5 - ) - - + - + 1 - - - + + + + h - ± - 2.3 - 0.5 + - + 1 - - - - 2.3 - - - - - × - 2.3 - - - 10 - 8 - + + + + + + + + + + + + + ( + + + kg + pol + + ) + + + 2 + + + + + + + ( + + + mol + cat + + ) + + + + - + 1 - -
- - 34.23 - - - - 34.23 - - - + + + + h - - 34.23 - - - - ( - 4 - ) - - + - + 1 + + + + + + + dBi + + + + + + + + + + kg + pol + + 2 + + + + + + mol + cat - - - - ± - 34.23 - 0.04 + - + 1 - - - - 34.23 - - - - 34.23 - -
- - 56.78 - - - - 56.78 - - - + + + + h - - 56.78 - - + - + 1 + + + + + + + + + + + + + kg + + ( - 3 + pol ) - - - - - ± - 56.78 - 0.03 - - - - - - - - - - 56.78 - - - - - - - × - 56.78 - - - 10 - 3 - - - -
- - 3.76 - - - - 3.76 - - - - - - 3.76 - - + 2 + + + + + + mol + + ( - 2 + cat ) - - - - - ± - 3.76 - 0.02 - - - - - - - - ± - 3.76 - - - - - - - - - - - 10 - 6 - - - -
-
- - - 3.0.4 - 3.0.4 - §3.0.4 - - <tag close=" ">3.0.4</tag>table-comparator - - - Table 17 - 17 - Table 17 - - 17Reserving space for comparators in S columns. - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 17Reserving space for comparators in S columns.
ValuesValues
- - 2.3 - - - - < - - - × - 2.3 - - - 10 - 8 - - + - + 1 - -
- - 34.23 - - - + + + + h - = - - 34.23 + - + 1 - -
- - 56.78 - - - - - - - - × - 56.78 - - - 10 - 3 + + + + + + dBi + + + + + + + + + + + + ( + + + kg + pol - + ) + + + 2 + + + + + + + ( + + + mol + cat + + ) + + + + - + 1 - -
- - 3.76 - - - + + + + h - - - - - - - - 10 - 6 - - + - + 1 - -
-
- - - 3.0.5 - 3.0.5 - §3.0.5 - - <tag close=" ">3.0.5</tag>table-format - - - Table 18 - 18 - Table 18 - - 18Using the table-format option. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 18Using the table-format option.
ValuesValuesValuesValuesValues
- - 2.3 - - - - 2.3 - - - + + + + + + + + + + + + + ( + + + kg + of + pol + + ) + + + 2 + + + + + + + ( + + + mol + of + cat + + ) + + - - 2.3 - - - - ( - 5 - ) - - + - + 1 - - - - 2.3 - - - - - × - 2.3 - - - 10 - 8 - + + + + h + + - + 1 - -
- - 34.23 - - - - 34.23 - - - + + + + + + + + + + + + + + + ( + kgbypol + ) + + + 2 + + + + + + + ( + molbycat + ) + + - - 34.23 - - - - ( - 4 - ) - - + - + 1 - - - - 34.23 - - - - 34.23 - -
- - 56.78 - - - - 56.78 - - - + + + + h - - 56.78 - - - - ( - 3 - ) - - + - + 1 - - - + + + +

+ + +

+ + + + + + kg - - - - - 56.78 - + + + ( + pol + ) + - -

- - - × - 56.78 - - - 10 - 3 + + 2 + + + + + + + + + kg + + + + ( + pol + ) + + + + 2 + + + + + + + + + + ( + + + kg + pol + + ) + + + 2 + + + + + + + + + + ( + + + kg + pol + ) + + + 2 + + + + + + + + + + ( + kgpol + ) + + + 2 + + + + + + + + + + ( + kgpol + ) + + + 2 + + +

+ + + + + 4.10.6 + subsubsection 4.10.6 + 4.10.6 + §4.10.6 + + <tag close=" ">4.10.6</tag>power-half-as-sqrt + +

+ + + + Hz + 0.5 + + + + + + + Hz + + +

+
+
+ + + 4.10.7 + subsubsection 4.10.7 + 4.10.7 + §4.10.7 + + <tag close=" ">4.10.7</tag>parse-units + +

+ + + + 300 + MHz + + + + + + + 300 + MHz + + + + + + + m + + + s + + - + 1 - -

- - 3.76 - - - - 3.76 - - - + + + + + + + / + m + s + + +

+ + + + + 4.10.8 + subsubsection 4.10.8 + 4.10.8 + §4.10.8 + + <tag close=" ">4.10.8</tag>forbid-literal-units + +

+ + + / + m + s + + + + + + + m + + + s - - 3.76 - - - - ( - 2 - ) - - - - -

- - - - - ± - 3.76 - - - - - - - - - - - 10 - 6 - + - + 1 - -
-
- - - 3.0.6 - 3.0.6 - §3.0.6 - - <tag close=" ">3.0.6</tag>table-space-text-pre, table-space-text-post - + + + +

+ + + - Table 19 - 19 - Table 19 + 4.10.9 + subsubsection 4.10.9 + 4.10.9 + §4.10.9 - 19Text before and after numbers. - - - - - - - - - - - - - - - - - - - - -
Table 19Text before and after numbers.
Values
- - 2.3456 - -
- - 34.2345 - - a
- - 56.7835 - -
now  90.473
-
- + <tag close=" ">4.10.9</tag>unit-font-command + +

+ + lm + + + + lm + +

+
+
+ + - 3.0.7 - 3.0.7 - §3.0.7 + 4.11 + subsection 4.11 + 4.11 + §4.11 - <tag close=" ">3.0.7</tag>table-align-comparator, table-align-exponent, table-align-uncertainty - + <tag close=" ">4.11</tag>Quantities + - Table 20 - 20 - Table 20 + 4.11.1 + subsubsection 4.11.1 + 4.11.1 + §4.11.1 - 20The table-align-exponent option - - - - - - - - - - - - - - - - - - - -
Table 20The table-align-exponent option
HeaderHeader
- - - × - 1.2 - - - 10 - 3 + 4.11.1allow-quantity-breaks + + +

X         + + + + 10 + m + + +

+

X         + + + + 10 + m + + +

+

X         + + + + 10 + m + + +

+

X         + + + + 10 + m + + +

+ + + + + + 4.11.2 + subsubsection 4.11.2 + 4.11.2 + §4.11.2 + + <tag close=" ">4.11.2</tag>quantity-product + +

+ + + + 2.67 + F + + + + + + + 2.67 + F + + + + + + + 2.67 + F + + + + + + + 2.67 + F + + + + + + + 2.67 + F + + + + + + × + 2.67 + F + + + + + + × + 2.67 + F + + + also + + + × + + + + ( + + ± + 3.7 + 4.5 + ) + + + F + + +

+
+
+ + + 4.11.3 + subsubsection 4.11.3 + 4.11.3 + §4.11.3 + + <tag close=" ">4.11.3</tag>prefix-mode, extract-mass-in-kilograms + +

+ + + + + × + 1 + + + 10 + 3 - -

- - - × - 1.2 - - - 10 - 3 - + + + + m + s + + + + + + + + 1 + + + km + s + + + + + + + + 10 + + + + + kg + 2 - -
- - - × - 1.234 - - - 10 - 56 + ds + + + + + + + + + × + 10 + + + 10 + + - + 1 - - - - - × - 1.234 - - - 10 - 56 + + + + + + kg + 2 + + s + + + + + + + + + × + 7.5 + + + 10 + + - + 3 - -
- - - Table 21 - 21 - Table 21 - - 21The table-align-uncertainty option - - - - - - - - - - - - - - - - - - - -
Table 21The table-align-uncertainty option
HeaderHeader
- + + kg + + + + + + + + + 10 + + + + + kg + 2 + + ds + + + + + + + + + × + 10 + + + 10 + 5 + + + + + + + g + 2 + + s + + + + + + + + 7.5 + g + + +

+ + +

+ + + + ml + + + mol - ± - 1.2 - 0.1 + - + 1 - -

- + + dA + + + + + + + ml + + + mol - ± - 1.2 - 0.3 + - + 1 - -
- - - ± - 1.234 - 0.005 + + dA + + + + + + + + + kg + 2 + + ds + + + + + + + + + Mg + 2 + + ds + + + + + + + + + Mg + 2 + + ds + + + + + + + + + + + µ + g - - - - - ± - 1.234 - 0.005 + 2 + + ds + + + + + + + + + + + µ + g - -
- - - Table 22 - 22 - Table 22 - - 22The table-align-comparator option - - - - - - - - - - - - - - - - - - - -
Table 22The table-align-comparator option
HeaderHeader
- + 2 + + ds + + + + + + + + + Mg - > - - 1.2 + - + 2 - - - + + ds + + + + + + + + + Mg - > - - 1.2 + - + 2 + + + ds + + + + + + + + + + + µ + g - -
- - < - - 12.34 + - + 2 + + + ds + + + + + + + + + + + µ + g - - - - < - - 12.34 + - + 2 - -
- - + + ds + + +

+ +
+ + + 4.11.4 + subsubsection 4.11.4 + 4.11.4 + §4.11.4 + + <tag close=" ">4.11.4</tag>separate-uncertainty-units + +

+ + + + + + + ( + + ± + 12.3 + 0.4 + + ) + + + kg + + + + + + + + + + ( + + ± + 12.3 + 0.4 + + ) + + + kg + + + + + + ± + + + 12.3 + kg + + + + 4 + kg + + + + + + + + + ± + 12.3 + 0.4 + + kg + + +

+
+
+
+ - 3.0.8 - 3.0.8 - §3.0.8 + 4.12 + subsection 4.12 + 4.12 + §4.12 - <tag close=" ">3.0.8</tag>table-omit-exponent - + <tag close=" ">4.12</tag>Tabular Material + - Table 23 - 23 - Table 23 + 4.12.1 + subsubsection 4.12.1 + 4.12.1 + §4.12.1 - 23The table-omit-exponent option - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.12.2 + subsubsection 4.12.2 + 4.12.2 + §4.12.2 + + <tag close=" ">4.12.2</tag>table-number-alignment + +

Aligning the S column

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.12.3 + subsubsection 4.12.3 + 4.12.3 + §4.12.3 + + <tag close=" ">4.12.3</tag>table-format + +

Reserving space in S columns

+ +
+ + + + + + + + + + + + + + - - - - - + - + + - - - + + + + + - + - - - + + + + + + + - + + + + + + + + + + + - - - -
Table 23The table-omit-exponent option
HeaderHeader / - - - - - - - 10 - 3 + 4.12.1table-alignment-mode + +

Parsing without aligning in an S column

+ +
Decimal-centeredSimple centering
+ + 12.345 + + + + 12.345 + +
+ + 6.78 + + + + 6.78 + +
+ + + - + + + 88.8 + + + + ( + 9 + ) + + + + + + + + + - + + + 88.8 + + + + ( + 9 + ) + + + + + +
+ + + × + + + 4.5 + + + + + 10 + 3 + + + + + + + × + 4.5 + + + 10 + 3 + + + +
Some ValuesSome ValuesSome ValuesSome Values
+ + 2.3456 + + + + 2.3456 + + + + 2.3456 + + + + 2.3456 + +
+ + 34.2345 + + + + 34.2345 + + + + 34.2345 + + + + 34.2345 + +
+ + 56.7835 + + + + 56.7835 + + + + 56.7835 + + + + 56.7835 + +
+ + 90.473 + + + + 90.473 + + + + 90.473 + + + + 90.473 + +
ValuesValuesValuesValuesValuesValues
+ + 2.3 + + + + 2.3 + + + + + + 2.3 + + + + ( + 5 + ) + + - - -
- - - × - 1.2 - - - 10 - 3 + + + + + ± + + + 2.3 + + + 0.5 - - - - - - × - 1.2 - - - 10 - 3 + + + + 2.3 + + + + + × + + + 2.3 + + + + + 10 + 8 + - - -
- - - × - 3 - - - 10 - 2 + +
+ + 34.23 + + + + 34.23 + + + + + + 34.23 + + + + ( + 4 + ) + + - - - - - - × - 3 - - - 10 - 2 + + + + + ± + 34.23 + 0.04 - - -
- - - × - 1.0 - - - 10 - 4 + + + + 34.23 + + + + 34.23 + +
+ + 56.78 + + + + 56.78 + + + + + + 56.78 + + + + ( + 3 + ) + + - - - - - - × - 1.0 - + + + + + ± + 56.78 + 0.03 + + + + + + - + 56.78 + + + + + + × + + + 56.78 + + + + + 10 + 3 + + + +
+ + 3.76 + + + + 3.76 + + + + + + 3.76 + + + + ( + 2 + ) + + + + + + + + ± + 3.76 + 0.02 + + + + + + ± + 3.76 + + + + + 10 - 4 + 6 - - -
- - - - 3.0.9 - 3.0.9 - §3.0.9 - - <tag close=" ">3.0.9</tag>table-align-text-pre,table-align-text-post - - - - 3.0.10 - 3.0.10 - §3.0.10 - - <tag close=" ">3.0.10</tag>table-auto-round - + + + + + + + + - Table 24 - 24 - Table 24 + 4.12.4 + subsubsection 4.12.4 + 4.12.4 + §4.12.4 - 24The table-auto-round option. - - - - - - - - - - - - - - - - - - - -
Table 24The table-auto-round option.
HeaderHeader
- - 1.2 - - - - 1.2 - -
- - 1.2345 - - - - 1.2345 - -
-
- - - 3.0.11 - 3.0.11 - §3.0.11 - - <tag close=" ">3.0.11</tag>parse-numbers - + <tag close=" ">4.12.4</tag>table-model-setup + + - Table 25 - 25 - Table 25 + 4.12.5 + subsubsection 4.12.5 + 4.12.5 + §4.12.5 - 25Aligning without parsing. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + +

The table-align-uncertainty option

+ +
+ + + + + + + + + + + + + + + + + + +

The table-align-comparator option

+ +
+ + + + + + + + + + + + + + + + + + +

Reserving space for comparators in S columns

+ +
+ + + + + + + + + + + - + + + + - + - - - - - - - - - - -
Table 25Aligning without parsing.
Some valuesSome valuesSome valuesSome values
- - 2.35 - - - - 2.35 - - - - 2.35 - - - - 2.35 - -
- - 34.234 - - - - 34.234 - - - - 34.234 - - - - 34.234 - -
- - 56.783 - - - - 56.783 - - - - 56.783 - - - - 56.783 - -
- - + 4.12.5table-align-[comparator|exponent|uncertainty] + +

The table-align-exponent option

+ +
HeaderHeader
+ + + × + + + 1.2 + + + + + 10 + 3 + + + + + + + × + 1.2 + + + 10 + 3 + + + +
+ + + × + + + 1.234 + + + + + 10 + 56 + + + + + + + × + 1.234 + + + 10 + 56 + + + +
HeaderHeader
+ + + ± + + + 1.2 + + + 0.1 + + + + + + ± + 1.2 + 0.3 + + +
+ + + ± + 1.234 + 0.005 + + + + + + ± + 1.234 + 0.005 + + +
HeaderHeader
+ + + > + + + + + 1.2 + + + + + + + > + + 1.2 + + +
+ + + < + + + + + 12.34 + + + + + + + < + + 12.34 + + +
ValuesValuesValues
+ + 2.3 + + + + + < + + + + + + × + + + 2.3 + + + + + 10 + 8 + + + + + + + - - - + < + + + × + + + 2.3 + + + + + 10 + 8 + + - - 3 - , - 762 - - - - - - + +
+ + 34.23 + + + - - - + = + + + + + 34.23 + - - 3 - , - 762 - - - - - - + + + - - - + = + + 34.23 - - 3 - , - 762 - - - - - - 3.762 - -
- - - - 2 - - - - - - - 2 - - - - - - - 2 - - - - - - - 2 - - -
-
- - - 3.0.12 - 3.0.12 - §3.0.12 - - <tag close=" ">3.0.12</tag>table-text-alignment - + + + + + + + + + + + + + + + + + + - Table 26 - 26 - Table 26 + 4.12.6 + subsubsection 4.12.6 + 4.12.6 + §4.12.6 - 26Aligning text in S columns. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + 56.78 + + + + + + + + + + + × + + + 56.78 + + + + + 10 + 3 + + + + + + + + + + + + × + + + 56.78 + + + + + 10 + 3 + + + + +
+ + 3.76 + + + + + + + + + + + + 10 + 6 + + + + + + + + + + + + 10 + 6 + + + +
Table 26Aligning text in S columns.
ValuesValuesValues
- - 992.435 - - - - 992.435 - - - - 992.435 - -
- - 7734.2344 - - - - 7734.2344 - - - - 7734.2344 - -
- - 56.7834 - - - - 56.7834 - - - - 56.7834 - -
- - 3.7462 - - - - 3.7462 - - - - 3.7462 - -
-
- - - 3.0.13 - 3.0.13 - §3.0.13 - - <tag close=" ">3.0.13</tag>table-unit-alignment - + <tag close=" ">4.12.6</tag>table-align-text-[before|after] + +

Closing notes up to text

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Table 27 - 27 - Table 27 + 4.12.7 + subsubsection 4.12.7 + 4.12.7 + §4.12.7 - 27Alignment options in s columns. - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + 4.12.8 + subsubsection 4.12.8 + 4.12.8 + §4.12.8 + + <tag close=" ">4.12.8</tag>parse-numbers + +

Aligning without parsing

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.12.9 + subsubsection 4.12.9 + 4.12.9 + §4.12.9 + + <tag close=" ">4.12.9</tag>drop-exponent + +

The drop-exponent option

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + 4.12.10 + subsubsection 4.12.10 + 4.12.10 + §4.12.10 + + <tag close=" ">4.12.10</tag>table-column-width, table-fixed-width + +

Fixed-width columns

+ +
+ + + + + + + + + + + + + + + + + + +

Right-aligning under a heading

+ +
+ + + + + + + + + + + + + + + + + + + + + 4.12.11 + subsubsection 4.12.11 + 4.12.11 + §4.12.11 + + <tag close=" ">4.12.11</tag>table-text-alignment, table-alignment + +

Aligning text in S columns

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.12.12 + subsubsection 4.12.12 + 4.12.12 + §4.12.12 + + <tag close=" ">4.12.12</tag>table-alignment + + + + + 4.13 + subsection 4.13 + 4.13 + §4.13 + + <tag close=" ">4.13</tag>Locale Options + +

+ + + + 1.234 + m + + + + + + + + + + 6 + , + 789 + + + m + + +

+
+
+ + + 4.14 + subsection 4.14 + 4.14 + §4.14 + + <tag close=" ">4.14</tag>Preamble-only options + +

These are in a different file. We check that trying to change the options has no effect here:

+
+ +

+ + + + + + + + + + 1 + , + 2 + and + 3 + + + + + + + × + + × + 1 + 2 + + 3 + + + Table check: +

+ + + + + + + + + + + + + + + + - + - + + + - - - - - - - - -
ValuesValues
+ + 2.3456 + + + + 2.3456 + +
a + + 4.234 + + a + + 4.234 + +
b + + 0.78 + + b + + 0.78 + +
d + + 88 + + d + + 88 + +
ValuesValues
+ + 2.3456 + + + + 2.3456 + +
+ + 34.234 + + a + + 34.234 + + a
+ + 56.78 + + b + + 56.78 + + b
+ + 90.4 + + c + + 90.4 + + c
+ + 88 + + d + + 88 + + d
Table 27Alignment options in s columns.
Right-alignedCentred textLeft-aligned
- - - - m - + 4.12.7table-auto-round + +

The table-auto-round option

+ +
HeaderHeader
+ + 1.2 + + + + 1.200 + +
+ + 1.2345 + + + + 1.235 + +
Some valuesSome valuesSome valuesSome values
+ + 2.35 + + + + 2.35 + + + + 2.35 + + + + 2.35 + +
+ + 34.234 + + + + 34.234 + + + + 34.234 + + + + 34.234 + +
+ + 56.783 + + + + 56.783 + + + + 56.783 + + + + 56.783 + +
+ + + + + + + + + 3 + , + 762 + + + + + + + + + + + + + 3 + , + 762 + + + + + + + + + + + + + 3 + , + 762 + + + + + + 3.762 + +
+ + + + 2 + + + + + + + 2 + + + + + + + 2 + + + + + + + 2 + + +
HeaderHeader / + + - s + 10 + 3 + + +
+ + + × + + + 1.2 + + + + + 10 + 3 + + + + + + 1.2 + +
+ + + × + + + 3 + + + + + 10 + 2 + + + + + + 0.3 + +
+ + + × + + + 1.0 + + + + + 10 + 4 + + + + + + 10 + +
FlexibleFixed
+ + 1.23 + + + + 1.23 + +
+ + 45.6 + + + + 45.6 + +
Long header
+ + 12.33 + +
+ + 2 + +
+ + 1234 + +
ValuesValuesValues
+ + 992.435 + + + + 992.435 + + + + 992.435 + +
+ + 7734.2344 + + + + 7734.2344 + + + + 7734.2344 + +
+ + 56.7834 + + + + 56.7834 + + + + 56.7834 + +
+ + 3.7462 + + + + 3.7462 + + + + 3.7462 + +
Decimal-centeredSimple centering
+ + 12.345 + + + + 12.345 + +
+ + 6.78 + + + + 6.78 + +
+ + + - - - - 1 + + 88.8 + + + + ( + 9 + ) + + - - - - - - - m - - - s + + + + + - - - - 1 + + 88.8 + + + + ( + 9 + ) + + - - - - - - - m - - - s - - - - 1 + +
+ + + × + + + 4.5 + + + + + 10 + 3 - - -
- - kg - - - - kg - - - - kg - -
-
- + + + + + + × + 4.5 + + + 10 + 3 + + + + + + +

+ +
+
+
+ + 10 + section 10 + 10 + §10 + + <tag close=" ">10</tag>Hints for using siunitx + - 3.0.14 - 3.0.14 - §3.0.14 + 10.2 + subsection 10.2 + 10.2 + §10.2 - <tag close=" ">3.0.14</tag>table-alignment - - + <tag close=" ">10.2</tag>Adjusting \litre and \liter + +

+ + L + +

+
+
+ - 3.0.15 - 3.0.15 - §3.0.15 + 10.5 + subsection 10.5 + 10.5 + §10.5 - <tag close=" ">3.0.15</tag>table-column-width - - - Table 28 - 28 - Table 28 - - 28Fixed-width columns. - - - + <tag close=" ">10.5</tag>Expanding content in tables + +

Values as macros in S columns

+ +
- - - - + - - - - - - - + + + 1234 + + + -
Table 28Fixed-width columns.
FlexibleFixedFlexibleFixedSome Values
- - - - m - - - s - - - - 1 - - - - - + - - - m - - - s - - - - 1 - - - - - - - - 1.23 - - - - - 1.23 + 12 348.812 34
- - - - kg - cd - - - - - - - kg - cd - - - + - 45.6 + 12 348.812 34 - +
1234 - 45.6 + 8.8 -
1234 8.8 1234
- + +
+ + + 10.11 + subsection 10.11 + 10.11 + §10.11 + + <tag close=" ">10.11</tag>Special considerations for the <verbatim font="typewriter">\</verbatim><Math mode="inline" tex="\mathrm{kW}\text{\,}\mathrm{h}" text="kilowatt * hour" xml:id="S10.SS11.m1"> + <XMath> + <XMApp> + <XMText meaning="times" role="MULOP" xml:id="S10.SS11.m1.2"> </XMText> + <XMTok class="ltx_unit" meaning="kilowatt" role="ID" xml:id="S10.SS11.m1.1">kW</XMTok> + <XMTok class="ltx_unit" meaning="hour" role="ID" xml:id="S10.SS11.m1.3">h</XMTok> + </XMApp> + </XMath> + </Math> unit + +

+ + + + kW + h + + + + + + + kW + h + + + m + + - + 1 + + + + + + + + + + + + kWh + + + m + + - + 1 + + + + + + + + + kWh + + + m + + - + 1 + + + + + + + + + + cd + + + kW + + - + 1 + + + h + + + + + + + cd + + + kW + + - + 1 + + + + + h + + - + 1 + + + + + + + + + cd + + + kW + + - + 1 + + + + + h + + - + 1 + + + + +

+
+
+ + + 10.12 + subsection 10.12 + 10.12 + §10.12 + + <tag close=" ">10.12</tag>Prefixes and small angles + +

+ + + + + × + 1 + + + 10 + + - + 3 + + + + as + + + + + + + 1 + mas + + +

+
+
+ + + 10.17 + subsection 10.17 + 10.17 + §10.17 + + <tag close=" ">10.17</tag>Demonstrating prefixes + +

+ + Y + + + + + + + + 10 + 24 + + + + + ab

+
+
diff --git a/t/complex/siV2.pdf b/t/complex/siV2.pdf new file mode 100644 index 000000000..8dfa431ef Binary files /dev/null and b/t/complex/siV2.pdf differ diff --git a/t/complex/siV2.tex b/t/complex/siV2.tex new file mode 100644 index 000000000..f9840327c --- /dev/null +++ b/t/complex/siV2.tex @@ -0,0 +1,97 @@ +\documentclass{article} +\usepackage{siunitx}[=v2] +\DeclareSIQualifier\polymer{pol} +\DeclareSIQualifier\catalyst{cat} +\usepackage{amsmath} +\usepackage{booktabs} + +\newbox\slashbox +\setbox\slashbox\hbox{\verb|\|} +\def\Backslash{\copy\slashbox} + +\begin{document} + +% This file has two purposes: +% 1. test valid commands that give different results in siunitx v2 and v3 +% 2. test v2 commands and options that have no counterpart in v3 +% +% The section numbering matches the corresponding section from +% version two of the siunitx documentation. + +\num{\pi}\\ + +\setcounter{section}{4} +\setcounter{subsection}{3} +\subsection{The unit macros} +\newcommand{\showunit}[1]{#1 & \texttt{\Backslash#1} & \si{\csname#1\endcsname}} +Non-SI units whose values in SI units must be obtained experimentally +(that are deprecated in siunitx v3, but make sure we still have them): +\begin{center} +\begin{tabular}{lll}\toprule +Unit & Macro & Symbol \\\midrule +\showunit{clight}\\ +\showunit{electronmass}\\ +\showunit{bohr}\\ +\showunit{hartree}\\\bottomrule +\end{tabular} +\end{center} + +\setcounter{section}{5} +\setcounter{subsection}{4} +\subsection{Post-processing numbers} +\subsubsection{add-decimal-zero} +\num{10.}\\ +\num[add-decimal-zero = false]{123.} + +\subsection{Printing numbers} +\subsubsection{group-four-digits} +\num[group-four-digits]{1234567890.1234567890} + +\subsubsection{copy-complex-root, copy-decimal-marker} +\num[copy-complex-root]{1+2j}\\ +\num[copy-decimal-marker]{555,555} + +\subsection{Multi-part numbers} +\subsubsection{input-quotient} +\num{ 1 / 2e4 } \\ +\num{ 1e2 / 3e4 }\\ +\num[input-quotient=?]{ 1e2 ? 3e4 } + +\subsubsection{output-quotient} +\num[output-quotient = \text{ div }]{1 / 2} + +\subsubsection{quotient-mode} +\num{1 / 2e4} \\ +\num[quotient-mode = fraction]{1 / 2e4} + +\subsubsection{fraction-function} +{ +\sisetup{quotient-mode= fraction} +\num{1 / 1}\\ +\num[fraction-function= \dfrac]{1 / 2}\\ +%\num[fraction-function= \sfrac]{1 / 3}\\ +\num[fraction-function= \tfrac]{1 / 4} +} + +\setcounter{subsection}{11} +\subsection{Using units} +\subsubsection{qualifier-mode} +\si[qualifier-mode = phrase] +{\kilogram\polymer\squared\per\mole\catalyst\per\hour} + +\begin{table} +\centering +\caption{Units in tables.} +\label{tab:s:demo} +\begin{tabular}{s} +\toprule +\multicolumn{1}{c}{Unit} \\ +\midrule +\metre\squared\per\second \\ +\pascal \\ +m.s^{-1} \\ +\bottomrule +\end{tabular} +\end{table} + +\end{document} diff --git a/t/complex/siV2.xml b/t/complex/siV2.xml new file mode 100644 index 000000000..f9a9c9c4f --- /dev/null +++ b/t/complex/siV2.xml @@ -0,0 +1,548 @@ + + + + + + + + + + +

+ + π + +

+
+ + + 4.4 + 4.4 + §4.4 + + <tag close=" ">4.4</tag>The unit macros + +

Non-SI units whose values in SI units must be obtained experimentally +(that are deprecated in siunitx v3, but make sure we still have them):

+ + + + Unit + Macro + Symbol + + + + + clight + \clight + + + + + + + c + 0 + + + + + + + + electronmass + \electronmass + + + + + + + m + e + + + + + + + + bohr + \bohr + + + + + + + a + 0 + + + + + + + + hartree + \hartree + + + + + + + E + h + + + + + + + + +
+
+ + + 5.5 + 5.5 + §5.5 + + <tag close=" ">5.5</tag>Post-processing numbers + + + 5.5.1 + 5.5.1 + §5.5.1 + + <tag close=" ">5.5.1</tag>add-decimal-zero + +

+ + 10 + + + + 123 + +

+
+
+
+ + + 5.6 + 5.6 + §5.6 + + <tag close=" ">5.6</tag>Printing numbers + + + 5.6.1 + 5.6.1 + §5.6.1 + + <tag close=" ">5.6.1</tag>group-four-digits + +

+ + 12 3456 7890.1234 5678 90 + +

+
+
+ + + 5.6.2 + 5.6.2 + §5.6.2 + + <tag close=" ">5.6.2</tag>copy-complex-root, copy-decimal-marker + +

+ + + + + 1 + + + 2 + j + + + + + + + + + 555 + , + 555 + + + +

+
+
+
+ + + 5.7 + 5.7 + §5.7 + + <tag close=" ">5.7</tag>Multi-part numbers + + + 5.7.1 + 5.7.1 + §5.7.1 + + <tag close=" ">5.7.1</tag>input-quotient + +

+ + + / + 1 + + + + + + + + ( + + × + 2 + + + 10 + 4 + + + ) + + + + + + + + / + + × + 1 + + + 10 + 2 + + + + + + + + + + ( + + × + 3 + + + 10 + 4 + + + ) + + + + + + + + / + + × + 1 + + + 10 + 2 + + + + + + + + + + ( + + × + 3 + + + 10 + 4 + + + ) + + + + +

+
+
+ + + 5.7.2 + 5.7.2 + §5.7.2 + + <tag close=" ">5.7.2</tag>output-quotient + +

+ + + div + 1 + 2 + + +

+
+
+ + + 5.7.3 + 5.7.3 + §5.7.3 + + <tag close=" ">5.7.3</tag>quotient-mode + +

+ + + / + 1 + + + + + + + + ( + + × + 2 + + + 10 + 4 + + + ) + + + + + + + + + 1 + + × + 2 + + + 10 + 4 + + + + +

+
+
+ + + 5.7.4 + 5.7.4 + §5.7.4 + + <tag close=" ">5.7.4</tag>fraction-function + +

+ + + + 1 + 1 + + + + + + + 1 + 2 + + + + + + + 1 + 4 + + +

+
+
+
+ + + 5.12 + 5.12 + §5.12 + + <tag close=" ">5.12</tag>Using units + + + 5.12.1 + 5.12.1 + §5.12.1 + + <tag close=" ">5.12.1</tag>qualifier-mode + +

+ + + + + + + + + ( + kgpol + ) + + + 2 + + + + + + + ( + molcat + ) + + + + - + 1 + + + + + h + + - + 1 + + + + +

+
+ + + Table 1 + 1 + Table 1 + + 1Units in tables. + + + + + + + + + + + + + + + + + + + +
Table 1Units in tables.
Unit
+ + + + + + m + 2 + + + + s + + - + 1 + + + + +
+ + Pa + +
+ + + + + + + + + m + . + + + s + + - + 1 + + + + + +
+
+
+
diff --git a/t/complex/siV3.pdf b/t/complex/siV3.pdf new file mode 100644 index 000000000..19f3acc15 Binary files /dev/null and b/t/complex/siV3.pdf differ diff --git a/t/complex/siV3.tex b/t/complex/siV3.tex new file mode 100644 index 000000000..6e4bb542e --- /dev/null +++ b/t/complex/siV3.tex @@ -0,0 +1,59 @@ +\documentclass{article} +\usepackage{siunitx}%[=v2] +\DeclareSIQualifier\polymer{pol} +\DeclareSIQualifier\catalyst{cat} +\usepackage{booktabs} +\begin{document} + +% This file tests valid commands that give different results in siunitx v2 and v3 + +\num{10.}\\ +\num[add-decimal-zero = false]{123.} + +\setcounter{section}{4} +\setcounter{subsection}{4} +\setcounter{subsubsection}{1} + +\subsubsection{exponent-thresholds} +Table \ref{tab:threshold} +\begin{table} +\caption{Thresholds for exponents.% +\label{tab:threshold}} +\begin{tabular} +{ +@{} +S +S[exponent-mode = threshold] +S[exponent-mode = threshold, exponent-thresholds = -2:2] +@{} +} +\toprule +{Input} & {Threshold $-3:3$} & {Threshold $-2:2$} \\ +\midrule +0.001 & 0.001 & 0.001 \\ +0.012 & 0.012 & 0.012 \\ +0.123 & 0.123 & 0.123 \\ +1 & 1 & 1 \\ +12 & 12 & 12 \\ +123 & 123 & 123 \\ +1234 & 1234 & 1234 \\ +\bottomrule +\end{tabular} +\end{table} + +\setcounter{section}{4} +\setcounter{subsection}{5} +\setcounter{subsubsection}{15} + +\subsubsection{zero-decimal-as-symbol, zero-symbol} +\num[zero-decimal-as-symbol]{123.} + +\setcounter{subsection}{10} +\setcounter{subsubsection}{4} + +\subsubsection{qualifier-[mode\textbar phrase]} +\unit[qualifier-mode = phrase] +{\kilogram\polymer\squared\per\mole\catalyst\per\hour} + + +\end{document} diff --git a/t/complex/siV3.xml b/t/complex/siV3.xml new file mode 100644 index 000000000..f85993498 --- /dev/null +++ b/t/complex/siV3.xml @@ -0,0 +1,347 @@ + + + + + + + + + +

+ + 10 + + + + 123 + +

+
+ + + 4.4.2 + 4.4.2 + §4.4.2 + + <tag close=" ">4.4.2</tag>exponent-thresholds + +

Table

+
+ + + Table 1 + 1 + Table 1 + + 1Thresholds for exponents. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1Thresholds for exponents.
InputThreshold + + + : + + - + 3 + + 3 + + + Threshold + + + : + + - + 2 + + 2 + + +
+ + 0.001 + + + + + × + + + 1 + + + + + 10 + + - + 3 + + + + + + + + × + + + 1 + + + + + 10 + + - + 3 + + + + +
+ + 0.012 + + + + 0.012 + + + + + × + + + 1.2 + + + + + 10 + + - + 2 + + + + +
+ + 0.123 + + + + 0.123 + + + + 0.123 + +
+ + 1 + + + + 1 + + + + 1 + +
+ + 12 + + + + 12 + + + + 12 + +
+ + 123 + + + + 123 + + + + + × + + + 1.23 + + + + + 10 + 2 + + + +
+ + 1234 + + + + + × + + + 1.234 + + + + + 10 + 3 + + + + + + + × + + + 1.234 + + + + + 10 + 3 + + + +
+
+ + + 4.5.16 + 4.5.16 + §4.5.16 + + <tag close=" ">4.5.16</tag>zero-decimal-as-symbol, zero-symbol + +

+ + + + + + 123 + + + + +

+
+
+ + + 4.10.5 + 4.10.5 + §4.10.5 + + <tag close=" ">4.10.5</tag>qualifier-[mode|phrase] + +

+ + + + + + + + + ( + kgpol + ) + + + 2 + + + + + + + ( + molcat + ) + + + + - + 1 + + + + + h + + - + 1 + + + + +

+
+
+
diff --git a/t/complex/si_preamble.pdf b/t/complex/si_preamble.pdf new file mode 100644 index 000000000..f8215deb9 Binary files /dev/null and b/t/complex/si_preamble.pdf differ diff --git a/t/complex/si_preamble.tex b/t/complex/si_preamble.tex new file mode 100644 index 000000000..5790df66b --- /dev/null +++ b/t/complex/si_preamble.tex @@ -0,0 +1,62 @@ +% these are options that can only be changed in the preamble or on package load +\documentclass{article} +\usepackage[ + list-input-separator=:, % only on package load + product-input-separator=*, % only on package load + table-column-type=T % only in preamble +]{siunitx} +%\usepackage{babel} % affects the range phrase (even in english) + +\usepackage{booktabs} +\providecommand{\toprule}{\hline} +\providecommand{\midrule}{\hline} +\providecommand{\bottomrule}{\hline} + + +\begin{document} + +%\tableofcontents + +\setcounter{section}{3} +\section{Package Control Options} + +\setcounter{subsection}{13} +\subsection{Preamble-only options} + +\subsubsection{list-input-separator, product-input-separator} + +\numlist{10:30:45} + +\numproduct{4 * 5 * 6} + +\subsubsection{table-column-type} + +\begin{table}[h] +\caption{Aligning the \texttt{T} (n\'ee \texttt{S}) column.% +\label{tab:S:align}} +\centering +\sisetup{table-format = 2.4, table-alignment-mode = format} +\begin{tabular}{@{} +T[table-alignment-mode = marker] +T[table-number-alignment = center] +T[table-number-alignment = left] +T[table-number-alignment = right] +@{}} +\toprule +{Some Values} & {Some Values} & {Some Values} & {Some Values} \\ +\midrule +2.3456 & 2.3456 & 2.3456 & 2.3456 \\ +34.2345 & 34.2345 & 34.2345 & 34.2345 \\ +56.7835 & 56.7835 & 56.7835 & 56.7835 \\ +90.473 & 90.473 & 90.473 & 90.473 \\ +\bottomrule +\end{tabular} +\end{table} + +\setcounter{section}{7} + +\section{Localisation} + +\numrange{10}{20} + +\end{document} diff --git a/t/complex/si_preamble.xml b/t/complex/si_preamble.xml new file mode 100644 index 000000000..462af6643 --- /dev/null +++ b/t/complex/si_preamble.xml @@ -0,0 +1,213 @@ + + + + + + + + +
+ + 4 + 4 + §4 + + <tag close=" ">4</tag>Package Control Options + + + 4.14 + 4.14 + §4.14 + + <tag close=" ">4.14</tag>Preamble-only options + + + 4.14.1 + 4.14.1 + §4.14.1 + + <tag close=" ">4.14.1</tag>list-input-separator, product-input-separator + +

+ + + + + + + + + + 10 + , + 30 + and + 45 + + + +

+
+ +

+ + + × + + × + 4 + 5 + + 6 + + +

+
+
+ + + 4.14.2 + 4.14.2 + §4.14.2 + + <tag close=" ">4.14.2</tag>table-column-type + + + Table 1 + 1 + Table 1 + + 1Aligning the T (née S) column. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1Aligning the T (née S) column.
Some ValuesSome ValuesSome ValuesSome Values
+ + 2.3456 + + + + 2.3456 + + + + 2.3456 + + + + 2.3456 + +
+ + 34.2345 + + + + 34.2345 + + + + 34.2345 + + + + 34.2345 + +
+ + 56.7835 + + + + 56.7835 + + + + 56.7835 + + + + 56.7835 + +
+ + 90.473 + + + + 90.473 + + + + 90.473 + + + + 90.473 + +
+
+
+
+
+ + 8 + 8 + §8 + + <tag close=" ">8</tag>Localisation + +

+ + + + + + + + + 10 + to + 20 + + + +

+
+
+