summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/didec/didec.sty
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/didec/didec.sty')
-rw-r--r--macros/latex/contrib/didec/didec.sty1349
1 files changed, 1349 insertions, 0 deletions
diff --git a/macros/latex/contrib/didec/didec.sty b/macros/latex/contrib/didec/didec.sty
new file mode 100644
index 0000000000..885e28b258
--- /dev/null
+++ b/macros/latex/contrib/didec/didec.sty
@@ -0,0 +1,1349 @@
+%% The LaTeX package didec - version 1.0.0 (2024/02/28)
+%% didec.sty: numbers with two decimal places
+%% !TeX encoding=UTF-8
+%%
+%% -------------------------------------------------------------------------------------------
+%% Copyright (c) 2024-2024 by Prof. Dr. Dr. Thomas F. Sturm <thomas dot sturm at unibw dot de>
+%% -------------------------------------------------------------------------------------------
+%%
+%% This work may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%% and version 1.3 or later is part of all distributions of LaTeX
+%% version 2005/12/01 or later.
+%%
+%% This work has the LPPL maintenance status `author-maintained'.
+%%
+%% This work consists of all files listed in README.md
+%%
+\NeedsTeXFormat{LaTeX2e}[2023-11-01]
+\ProvidesExplPackage{didec}{2024/02/28}{1.0.0}
+ {Fixed-point arithmetic with two decimal places}
+
+%------- package options -------------------
+
+\DeclareKeys
+ {
+ int .code:n =
+ {
+ \prg_set_conditional:Nnn \didec_if_kernel_int: { p, T, TF } { \prg_return_true: }
+ \prg_set_conditional:Nnn \didec_if_kernel_fp: { p, T, TF } { \prg_return_false: }
+ },
+ fp .code:n =
+ {
+ \prg_set_conditional:Nnn \didec_if_kernel_int: { p, T, TF } { \prg_return_false: }
+ \prg_set_conditional:Nnn \didec_if_kernel_fp: { p, T, TF } { \prg_return_true: }
+ },
+ }
+
+\ProcessKeyOptions
+
+\cs_if_exist:NF \didec_if_kernel_int_p:
+ {
+ \SetKeys{ int }
+ }
+
+%------- integer kernel (int) -------------------
+
+\if_predicate:w \didec_if_kernel_int_p:
+
+\str_const:Nn \c_didec_kernel_str { int }
+
+% <int>
+% test on existence of didec variable #1
+% adapted from \cs_if_exist:c
+\prg_new_conditional:Npnn \didec_if_exist:n #1 { p, T, F, TF }
+ {
+ \if_cs_exist:w g_didec_var_#1_int \cs_end:
+ \exp_after:wN \use_i:nn
+ \else:
+ \exp_after:wN \use_ii:nn
+ \fi:
+ {
+ \exp_after:wN \if_meaning:w \cs:w g_didec_var_#1_int \cs_end: \scan_stop:
+ \prg_return_false:
+ \else:
+ \prg_return_true:
+ \fi:
+ }
+ \prg_return_false:
+ }
+
+% <int>
+% #1 integer value
+\prg_new_conditional:Npnn \__didec_if_negative:n #1 { TF }
+ {
+ \if_int_compare:w #1 < \c_zero_int
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+
+% <int>
+% #1 didec variable
+\prg_new_conditional:Npnn \didec_if_negative:n #1 { p, T, F, TF }
+ {
+ \if_int_compare:w \didec_to_int:n { #1 } < \c_zero_int
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+
+% <int>
+% #1 didec variable
+\prg_new_conditional:Npnn \didec_if_positive:n #1 { p, T, F, TF }
+ {
+ \if_int_compare:w \didec_to_int:n { #1 } > \c_zero_int
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+
+% <int>
+% #1 didec variable
+\prg_new_conditional:Npnn \didec_if_zero:n #1 { p, T, F, TF }
+ {
+ \if_int_compare:w \didec_to_int:n { #1 } = \c_zero_int
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+
+% <int>
+% #1 didec variable
+% #2 relation
+% #3 didec variable
+\prg_new_conditional:Npnn \didec_compare:nNn #1#2#3 { p, T, F, TF }
+ {
+ \if_int_compare:w \__didec_eval:n { #1 } #2 \__didec_eval:n { #3 }
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+
+% <int>
+% #1 didec variable
+\cs_new:Npn \didec_to_int:n #1
+ {
+ \int_use:c { g_didec_var_#1_int }
+ }
+
+% <int>
+% #1 didec variable
+\cs_new_protected:Npn \didec_new:n #1
+ {
+ \didec_if_exist:nTF { #1 }
+ {
+ \msg_error:nne { didec }{ already-defined }{ #1 }
+ }
+ {
+ \int_new:c { g_didec_var_#1_int }
+ }
+ }
+
+% <int>
+% Sets didec variable #1 to the current value of didec variable #2
+\cs_new_protected:Npn \didec_gset_eq:nn #1#2
+ {
+ \int_gset_eq:cc { g_didec_var_#1_int }{ g_didec_var_#2_int }
+ }
+
+% <int>
+% set didec variable #1 to integer value #2
+\cs_new_protected:Npn \__didec_gset_int:nn #1#2
+ {
+ \int_gset:cn { g_didec_var_#1_int }{ #2 }
+ }
+
+% <int>
+% add integer #2 to didec variable #1
+\cs_new_protected:Npn \__didec_gadd_int:nn #1#2
+ {
+ \int_gadd:cn { g_didec_var_#1_int }{ #2 }
+ }
+
+\fi:
+
+%------- floating point kernel (fp) -------------------
+
+\if_predicate:w \didec_if_kernel_fp_p:
+
+\str_const:Nn \c_didec_kernel_str { fp }
+
+% <fp>
+% test on existence of didec variable #1
+% adapted from \cs_if_exist:c
+\prg_new_conditional:Npnn \didec_if_exist:n #1 { p, T, F, TF }
+ {
+ \if_cs_exist:w g_didec_var_#1_fp \cs_end:
+ \exp_after:wN \use_i:nn
+ \else:
+ \exp_after:wN \use_ii:nn
+ \fi:
+ {
+ \exp_after:wN \if_meaning:w \cs:w g_didec_var_#1_fp \cs_end: \scan_stop:
+ \prg_return_false:
+ \else:
+ \prg_return_true:
+ \fi:
+ }
+ \prg_return_false:
+ }
+
+% <fp>
+% #1 large integer value
+\prg_new_conditional:Npnn \__didec_if_negative:n #1 { TF }
+ {
+ \exp_last_unbraced:Ne \token_if_eq_charcode:NNTF { \tl_head:n { #1 } }{ - }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+ }
+
+% <fp>
+% #1 didec variable
+\prg_new_conditional:Npnn \didec_if_negative:n #1 { p, T, F, TF }
+ {
+ \exp_last_unbraced:Ne \token_if_eq_charcode:NNTF { \exp_args:Ne \tl_head:n { \didec_to_int:n { #1 } } }{ - }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+ }
+
+% <fp>
+% #1 didec variable
+\prg_new_conditional:Npnn \didec_if_positive:n #1 { p, T, F, TF }
+ {
+ \exp_args:Ne \__didec_if_positive_token:n { \exp_args:Ne \tl_head:n { \didec_to_int:n { #1 } } }
+ }
+
+% <fp>
+% #1 didec variable
+\cs_new:Npn \__didec_if_positive_token:n #1
+ {
+ \token_if_eq_charcode:NNTF { #1 }{ - }
+ {
+ \prg_return_false:
+ }
+ {
+ \token_if_eq_charcode:NNTF { #1 }{ 0 }
+ {
+ \prg_return_false:
+ }
+ {
+ \prg_return_true:
+ }
+ }
+ }
+
+% <fp>
+% #1 didec variable
+\prg_new_conditional:Npnn \didec_if_zero:n #1 { p, T, F, TF }
+ {
+ \exp_last_unbraced:Ne \token_if_eq_charcode:NNTF { \exp_args:Ne \tl_head:n { \didec_to_int:n { #1 } } }{ 0 }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+ }
+
+% <fp>
+% #1 didec variable
+% #2 relation
+% #3 didec variable
+\prg_new_conditional:Npnn \didec_compare:nNn #1#2#3 { p, T, F, TF }
+ {
+ \fp_compare:nNnTF { \__didec_eval:n { #1 } } #2 { \__didec_eval:n { #3 } }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+ }
+
+% <fp>
+% #1 didec variable
+\cs_new:Npn \didec_to_int:n #1
+ {
+ \fp_use:c { g_didec_var_#1_fp }
+ }
+
+% <fp>
+% #1 didec variable
+\cs_new_protected:Npn \didec_new:n #1
+ {
+ \didec_if_exist:nTF { #1 }
+ {
+ \msg_error:nne { didec }{ already-defined }{ #1 }
+ }
+ {
+ \fp_new:c { g_didec_var_#1_fp }
+ }
+ }
+
+% <fp>
+% Sets didec variable #1 to the current value of didec variable #2
+\cs_new_protected:Npn \didec_gset_eq:nn #1#2
+ {
+ \fp_gset_eq:cc { g_didec_var_#1_fp }{ g_didec_var_#2_fp }
+ }
+
+% <fp>
+% set didec variable #1 to integer value #2
+\cs_new_protected:Npn \__didec_gset_int:nn #1#2
+ {
+ \fp_gset:cn { g_didec_var_#1_fp }{ #2 }
+ }
+
+% <fp>
+% add integer #2 to didec variable #1
+\cs_new_protected:Npn \__didec_gadd_int:nn #1#2
+ {
+ \fp_gadd:cn { g_didec_var_#1_fp }{ #2 }
+ }
+
+
+\fi:
+
+
+%------- didec variables -------------------
+
+
+\cs_new:Npn \__didec_if_exist_else_error:nT #1#2
+ {
+ \didec_if_exist:nTF { #1 }
+ {
+ #2
+ }
+ {
+ \msg_error:nne { didec }{ no-variable }{ #1 }
+ }
+ }
+
+
+% set didec variable #1 to didec expression #2
+% #1 didec variable
+% #2 didec expression
+\cs_new_protected:Npn \didec_gset:nn #1#2
+ {
+ \__didec_gset_int:nn { #1 }{ \__didec_eval:n { #2 } }
+ }
+
+
+% set didec variable #1 to didec expression #2
+% #1 didec variable
+% #2 didec expression
+\cs_new_protected:Npn \didec_gset_negative:nn #1#2
+ {
+ \__didec_gset_int:nn { #1 }{ - \__didec_eval:n { #2 } }
+ }
+
+
+% set didec variable #1 to floating-point expression #2
+% #1 didec variable
+% #2 floating-point expression
+\cs_new_protected:Npn \didec_gset_fp:nn #1#2
+ {
+ \__didec_gset_int:nn { #1 }{ \fp_to_int:n { (#2)*100 } }
+ }
+
+
+% add didec expression #2 to didec variable #1
+% #1 didec variable
+% #2 didec expression
+\cs_new_protected:Npn \didec_gadd:nn #1#2
+ {
+ \__didec_gadd_int:nn { #1 }{ \__didec_eval:n { #2 } }
+ }
+
+
+% add sum of didec expression #2 and #3 to didec variable #1
+% #1 didec variable
+% #2 didec expression
+% #3 didec expression
+\cs_new_protected:Npn \didec_gadd_to:nnn #1#2#3
+ {
+ \__didec_gset_int:nn { #1 }{ \__didec_eval:n { #2 } + \__didec_eval:n { #3 } }
+ }
+
+
+% subtract didec expression #2 from didec variable #1
+% #1 didec variable
+% #2 didec expression
+\cs_new_protected:Npn \didec_gsub:nn #1#2
+ {
+ \__didec_gadd_int:nn { #1 }{ - \__didec_eval:n { #2 } }
+ }
+
+
+% set didec variable #1 to the difference of didec expression #2 and #3
+% #1 didec variable
+% #2 didec expression
+% #3 didec expression
+\cs_new_protected:Npn \didec_gsub_to:nnn #1#2#3
+ {
+ \__didec_gset_int:nn { #1 }{ \__didec_eval:n { #2 } - \__didec_eval:n { #3 } }
+ }
+
+
+% multiply didec variable #1 with floating-point expression #2
+% #1 didec variable
+% #2 floating-point expression
+\cs_new_protected:Npn \didec_gmul_fp:nn #1#2
+ {
+ \__didec_gset_int:nn { #1 }{ \fp_to_int:n { \didec_to_int:n { #1 } * (#2) } }
+ }
+
+
+% set didec variable #1 to the product of didec variable #2 with floating-point expression #3
+% #1 didec variable
+% #2 didec variable
+% #3 floating-point expression
+\cs_new_protected:Npn \didec_gmul_fp_to:nnn #1#2#3
+ {
+ \__didec_gset_int:nn { #1 }{ \fp_to_int:n { \didec_to_int:n { #2 } * (#3) } }
+ }
+
+
+% divide didec variable #1 by floating-point expression #2
+% #1 didec variable
+% #2 floating-point expression
+\cs_new_protected:Npn \didec_gdiv_fp:nn #1#2
+ {
+ \__didec_gset_int:nn { #1 }{ \fp_to_int:n { \didec_to_int:n { #1 } / (#2) } }
+ }
+
+
+% set didec variable #1 to the quotient of didec variable #2 with floating-point expression #3
+% #1 didec variable
+% #2 didec variable
+% #3 floating-point expression
+\cs_new_protected:Npn \didec_gdiv_fp_to:nnn #1#2#3
+ {
+ \__didec_gset_int:nn { #1 }{ \fp_to_int:n { \didec_to_int:n { #2 } / (#3) } }
+ }
+
+
+%------- formatting didec variables -------------------
+
+
+% fp value of didec variable #1
+% #1 didec variable
+\cs_new:Npn \didec_to_fp:n #1
+ {
+ \exp_args:Nf \__didec_format:nn { \didec_to_int:n {#1} }{ . }
+ }
+
+
+% fp value of didec variable #1
+% #1 didec variable
+\cs_new:Npn \didec_to_fc:n #1
+ {
+ \exp_args:Nf \__didec_format:nn { \didec_to_int:n {#1} }{ , }
+ }
+
+
+% #1 (large) integer value (from didec variable)
+% #2 decimal separator
+\cs_new:Npn \__didec_format:nn #1#2
+ {
+ \__didec_if_negative:nTF { #1 }
+ { - \exp_args:No \__didec_format_pos:nn { \use_none:n #1 }{ #2 } }
+ { \__didec_format_pos:nn { #1 }{ #2 } }
+ }
+
+\cs_new:Npn \__didec_format_pos:nn #1#2
+ {
+ \exp_args:Ne \__didec_format_pos_i:w { \tl_count:n {#1} }{ #2 } #1 \q_nil \q_nil \q_nil \q_nil \q_nil \q_nil \q_stop
+ }
+
+\cs_new:Npn \__didec_format_pos_i:w #1#2#3#4#5#6#7#8#9 \q_stop
+ {
+ \if_case:w #1 \exp_stop_f:
+ \or: 0 #2 0 #3 % 1
+ \or: 0 #2 #3#4 % 2
+ \or: #3 #2 #4#5 % 3
+ \or: #3#4 #2 #5#6 % 4
+ \or: #3#4#5 #2 #6#7 % 5
+ \or: #3#4#5#6 #2 #7#8 % 6
+ \or: #3#4#5#6#7 #2 #8 \__didec_format_pos_ii:w { 0 }{ #2 } #9 \q_stop % 7
+ \or: #3#4#5#6#7#8 #2 \__didec_format_pos_ii:w { 1 }{ #2 } #9 \q_stop % 8
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 2 }{ #2 } #9 \q_stop % 9
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 3 }{ #2 } #9 \q_stop % 10
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 4 }{ #2 } #9 \q_stop % 11
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 5 }{ #2 } #9 \q_stop % 12
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 6 }{ #2 } #9 \q_stop % 13
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 7 }{ #2 } #9 \q_stop % 14
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 8 }{ #2 } #9 \q_stop % 15
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 9 }{ #2 } #9 \q_stop % 16
+ \else 0 #2 00 % error
+ \fi:
+ }
+
+\cs_new:Npn \__didec_format_pos_ii:w #1#2#3#4#5#6#7#8#9 \q_stop
+ {
+ \if_case:w #1 \exp_stop_f:
+ #3 % 0 = 7 = 13
+ \or: #3#4 % 1 = 8 = 14
+ \or: #3 #2 #4#5 % 2 = 9 = 15
+ \or: #3#4 #2 #5#6 % 3 = 10 = 16
+ \or: #3#4#5 #2 #6#7 % 4 = 11
+ \or: #3#4#5#6 #2 #7#8 % 5 = 12
+ \or: #3#4#5#6#7 #2 #8 \__didec_format_pos_ii:w { 0 }{ #2 } #9 \q_stop % 6 = 13
+ \or: #3#4#5#6#7#8 #2 \__didec_format_pos_ii:w { 1 }{ #2 } #9 \q_stop % 7 = 14
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 2 }{ #2 } #9 \q_stop % 8 = 15
+ \or: #3#4#5#6#7#8 \__didec_format_pos_ii:w { 3 }{ #2 } #9 \q_stop % 9 = 16
+ \fi:
+ }
+
+
+% #1 (large) integer value (from didec variable)
+% #2 positive extra
+% #3 negative extra
+\cs_new:Npn \__didec_format_group:nnn #1#2#3
+ {
+ \__didec_if_negative:nTF { #1 }
+ {
+ #3
+ \l__didec_currency_negative_prefix_tl
+ \exp_args:No \__didec_format_group_pos:nnn
+ { \use_none:n #1 }
+ { \l__didec_decimal_separator_tl }
+ { \l__didec_grouping_separator_tl }
+ \l__didec_currency_negative_postfix_tl
+ }
+ {
+ #2
+ \l__didec_currency_prefix_tl
+ \__didec_format_group_pos:nnn
+ { #1 }
+ { \l__didec_decimal_separator_tl }
+ { \l__didec_grouping_separator_tl }
+ \l__didec_currency_postfix_tl
+ }
+ }
+
+\cs_new:Npn \__didec_format_group_pos:nnn #1#2#3
+ {
+ \exp_args:Ne \__didec_format_group_pos_i:w { \tl_count:n {#1} }{ #2 }{ #3 } #1 \q_nil \q_nil \q_nil \q_nil \q_nil \q_stop
+ }
+
+\cs_new:Npn \__didec_format_group_pos_i:w #1#2#3#4#5#6#7#8#9 \q_stop
+ {
+ \if_case:w #1 \exp_stop_f:
+ \or: 0 #2 0 #4 % 1
+ \or: 0 #2 #4#5 % 2
+ \or: #4 #2 #5#6 % 3
+ \or: #4#5 #2 #6#7 % 4
+ \or: #4#5#6 #2 #7#8 % 5
+ \or: #4 #3 #5#6#7 #2 #8 \__didec_format_group_pos_ii:w { 0 }{ #2 }{ #3 } #9 \q_stop % 6
+ \or: #4#5 #3 #6#7#8 #2 \__didec_format_group_pos_ii:w { 1 }{ #2 }{ #3 } #9 \q_stop % 7
+ \or: #4#5#6 #3 #7#8 \__didec_format_group_pos_ii:w { 2 }{ #2 }{ #3 } #9 \q_stop % 8
+ \or: #4 #3 #5#6#7 #3 #8 \__didec_format_group_pos_ii:w { 3 }{ #2 }{ #3 } #9 \q_stop % 9
+ \or: #4#5 #3 #6#7#8 #3 \__didec_format_group_pos_ii:w { 4 }{ #2 }{ #3 } #9 \q_stop % 10
+ \or: #4#5#6 #3 #7#8 \__didec_format_group_pos_ii:w { 5 }{ #2 }{ #3 } #9 \q_stop % 11
+ \or: #4 #3 #5#6#7 #3 #8 \__didec_format_group_pos_ii:w { 6 }{ #2 }{ #3 } #9 \q_stop % 12
+ \or: #4#5 #3 #6#7#8 #3 \__didec_format_group_pos_ii:w { 7 }{ #2 }{ #3 } #9 \q_stop % 13
+ \or: #4#5#6 #3 #7#8 \__didec_format_group_pos_ii:w { 8 }{ #2 }{ #3 } #9 \q_stop % 14
+ \or: #4 #3 #5#6#7 #3 #8 \__didec_format_group_pos_ii:w { 9 }{ #2 }{ #3 } #9 \q_stop % 15
+ \or: #4#5 #3 #6#7#8 #3 \__didec_format_group_pos_ii:w { 10 }{ #2 }{ #3 } #9 \q_stop % 16
+ \else 1 #2 00 % error
+ \fi:
+ }
+
+\cs_new:Npn \__didec_format_group_pos_ii:w #1#2#3#4#5#6#7#8#9 \q_stop
+ {
+ \if_case:w #1 \exp_stop_f:
+ #4 % 0 = 6 = 11
+ \or: #4#5 % 1 = 7 = 12
+ \or: #4 #2 #5#6 % 2 = 8 = 13
+ \or: #4#5 #2 #6#7 % 3 = 9 = 14
+ \or: #4#5#6 #2 #7#8 % 4 = 10 = 15
+ \or: #4 #3 #5#6#7 #2 #8 \__didec_format_group_pos_ii:w { 0 }{ #2 }{ #3 } #9 \q_stop % 5 = 11 = 16
+ \or: #4#5 #3 #6#7#8 #2 \__didec_format_group_pos_ii:w { 1 }{ #2 }{ #3 } #9 \q_stop % 6 = 12
+ \or: #4#5#6 #3 #7#8 \__didec_format_group_pos_ii:w { 2 }{ #2 }{ #3 } #9 \q_stop % 7 = 13
+ \or: #4 #3 #5#6#7 #3 #8 \__didec_format_group_pos_ii:w { 3 }{ #2 }{ #3 } #9 \q_stop % 8 = 14
+ \or: #4#5 #3 #6#7#8 #3 \__didec_format_group_pos_ii:w { 4 }{ #2 }{ #3 } #9 \q_stop % 9 = 15
+ \or: #4#5#6 #3 #7#8 \__didec_format_group_pos_ii:w { 5 }{ #2 }{ #3 } #9 \q_stop % 10 = 16
+ \fi:
+ }
+
+
+% #1 didec variable
+% #2 stream
+\cs_new_protected:Npn \didec_write:nn #1#2
+ {
+ \iow_now:Ne #2
+ {
+ \c_backslash_str didecset
+ { #1 }
+ { \didec_to_fp:n { #1 } }
+ \c_percent_str
+ }
+ }
+
+
+% #1 didec variable
+% #2 stream
+\cs_new_protected:Npn \didec_write_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_write:nn { #1 }{ #2 }
+ }
+ }
+
+
+
+%------- number scanner -------------------
+
+% Evaluates #1 and leaves the result in the input stream as an integer denotation
+% #1 can be a single didec variable or a number with floating-comma or floating-point
+\cs_new:Npn \__didec_eval:n #1
+ {
+ \exp_args:Ne \__didec_eval_expanded:n { \exp_args:Ne \tl_trim_spaces:n { #1 } }
+ }
+
+
+\cs_new:Npn \__didec_eval_expanded:n #1
+ {
+ \didec_if_exist:nTF { #1 }
+ {
+ \didec_to_int:n { #1 }
+ }
+ {
+ \__didec_eval_p_a:w #1.\q_nil \q_stop
+ }
+ }
+
+
+\cs_new:Npn \__didec_eval_p_a:w #1.#2#3 \q_stop
+ {
+ \quark_if_nil:NTF #2
+ {
+ \__didec_eval_c_a:w #1,\q_nil\q_stop
+ }
+ {
+ #1\__didec_eval_p_b:w #2#3
+ }
+ }
+
+\cs_new:Npn \__didec_eval_p_b:w #1. \q_nil
+ {
+ \__didec_eval_c:w #1 00 \q_stop
+ }
+
+\cs_new:Npn \__didec_eval_c_a:w #1,#2#3 \q_stop
+ {
+ \quark_if_nil:NTF #2
+ {
+ #100
+ }
+ {
+ #1\__didec_eval_c_b:w #2#3
+ }
+ }
+
+\cs_new:Npn \__didec_eval_c_b:w #1, \q_nil
+ {
+ \__didec_eval_c:w #1 00 \q_stop
+ }
+
+\cs_new:Npn \__didec_eval_c:w #1#2#3 \q_stop
+ {
+ #1#2
+ }
+
+
+%------- didec variables (extended) -------------------
+
+% #1 didec variable
+\cs_new_protected:Npn \didec_show:n #1
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_if_kernel_int:T
+ {
+ \int_show:c { g_didec_var_#1_int }
+ }
+ \didec_if_kernel_fp:T
+ {
+ \fp_show:c { g_didec_var_#1_fp }
+ }
+ }
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_to_int_check:n #1
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_to_int:n { #1 }
+ }
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_to_fp_check:n #1
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_to_fp:n { #1 }
+ }
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_to_fc_check:n #1
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_to_fc:n { #1 }
+ }
+ }
+
+
+% set didec variable #1 to integer value #2
+\cs_new_protected:Npn \__didec_gset_int_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \__didec_gset_int:nn { #1 }{ #2 }
+ }
+ }
+
+% Sets didec variable #1 to the current value of didec variable #2
+\cs_new_protected:Npn \didec_gset_eq_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \__didec_if_exist_else_error:nT { #2 }
+ {
+ \didec_gset_eq:nn { #1 }{ #2 }
+ }
+ }
+ }
+
+% set didec variable #1 to didec expression #2
+% #1 didec variable
+% #2 didec expression
+\cs_new_protected:Npn \didec_gset_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gset:nn { #1 }{ #2 }
+ }
+ }
+
+% set didec variable #1 to didec expression #2
+% #1 didec variable
+% #2 didec expression
+\cs_new_protected:Npn \didec_gset_negative_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gset_negative:nn { #1 }{ #2 }
+ }
+ }
+
+% set didec variable #1 to floating-point expression #2
+% #1 didec variable
+% #2 floating-point expression
+\cs_new_protected:Npn \didec_gset_fp_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gset_fp:nn { #1 }{ #2 }
+ }
+ }
+
+% add didec expression #2 to didec variable #1
+% #1 didec variable
+% #2 didec expression
+\cs_new_protected:Npn \didec_gadd_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gadd:nn { #1 }{ #2 }
+ }
+ }
+
+% add sum of didec expression #2 and #3 to didec variable #1
+% #1 didec variable
+% #2 didec expression
+% #3 didec expression
+\cs_new_protected:Npn \didec_gadd_to_check:nnn #1#2#3
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gadd_to:nnn { #1 }{ #2 }{ #3 }
+ }
+ }
+
+% subtract didec expression #2 from didec variable #1
+% #1 didec variable
+% #2 didec expression
+\cs_new_protected:Npn \didec_gsub_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gsub:nn { #1 }{ #2 }
+ }
+ }
+
+% set didec variable #1 to the difference of didec expression #2 and #3
+% #1 didec variable
+% #2 didec expression
+% #3 didec expression
+\cs_new_protected:Npn \didec_gsub_to_check:nnn #1#2#3
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gsub_to:nnn { #1 }{ #2 }{ #3 }
+ }
+ }
+
+% multiply didec variable #1 with floating-point expression #2
+% #1 didec variable
+% #2 floating-point expression
+\cs_new_protected:Npn \didec_gmul_fp_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gmul_fp:nn { #1 }{ #2 }
+ }
+ }
+
+% set didec variable #1 to the product of didec variable #2 with floating-point expression #3
+% #1 didec variable
+% #2 didec variable
+% #3 floating-point expression
+\cs_new_protected:Npn \didec_gmul_fp_to_check:nnn #1#2#3
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gmul_fp_to:nnn { #1 }{ #2 }{ #3 }
+ }
+ }
+
+% divide didec variable #1 by floating-point expression #2
+% #1 didec variable
+% #2 floating-point expression
+\cs_new_protected:Npn \didec_gdiv_fp_check:nn #1#2
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gdiv_fp:nn { #1 }{ #2 }
+ }
+ }
+
+% set didec variable #1 to the quotient of didec variable #2 with floating-point expression #3
+% #1 didec variable
+% #2 didec variable
+% #3 floating-point expression
+\cs_new_protected:Npn \didec_gdiv_fp_to_check:nnn #1#2#3
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_gdiv_fp_to:nnn { #1 }{ #2 }{ #3 }
+ }
+ }
+
+
+%------- formatting didec variables (extended) -------------------
+
+\tl_new:N \l__didec_decimal_separator_tl
+\tl_new:N \l__didec_grouping_separator_tl
+\tl_new:N \l__didec_currency_prefix_tl
+\tl_new:N \l__didec_currency_postfix_tl
+\tl_new:N \l__didec_currency_negative_prefix_tl
+\tl_new:N \l__didec_currency_negative_postfix_tl
+
+\keys_define:nn { didec }
+ {
+ decimal-separator .tl_set:N = \l__didec_decimal_separator_tl,
+ grouping-separator .tl_set:N = \l__didec_grouping_separator_tl,
+ currency .code:n =
+ {
+ \tl_set:No \l__didec_currency_prefix_tl { \use_i:nn #1 }
+ \tl_set:No \l__didec_currency_postfix_tl { \use_ii:nn #1 }
+ \tl_set:No \l__didec_currency_negative_prefix_tl { \use_i:nn #1 - }
+ \tl_set:No \l__didec_currency_negative_postfix_tl { \use_ii:nn #1 }
+ },
+ currency-negative .code:n =
+ {
+ \tl_set:No \l__didec_currency_negative_prefix_tl { \use_i:nn #1 }
+ \tl_set:No \l__didec_currency_negative_postfix_tl { \use_ii:nn #1 }
+ },
+ german .meta:n =
+ {
+ decimal-separator = {,},
+ grouping-separator = {.},
+ currency = {}{},
+ },
+ english .meta:n =
+ {
+ decimal-separator = {.},
+ grouping-separator = {,},
+ currency = {}{},
+ },
+ french .meta:n =
+ {
+ decimal-separator = {,},
+ grouping-separator = {\;},
+ currency = {}{},
+ },
+ float .meta:n =
+ {
+ decimal-separator = {.},
+ grouping-separator = ,
+ currency = {}{},
+ },
+ color-positive .code:n =
+ {
+ \color_set:nn { didec-positive }{ #1 }
+ },
+ color-negative .code:n =
+ {
+ \color_set:nn { didec-negative }{ #1 }
+ },
+ }
+
+\color_set:nn { didec-gray }{ black!85!white }
+
+\color_set:nnn { didec-green }{ rgb }{ 0, 0.35, 0 }
+\color_set:nnn { didec-red }{ rgb }{ 0.35, 0, 0 }
+\color_set:nnn { didec-blue }{ rgb }{ 0, 0, 0.35 }
+
+
+\keys_set:nn { didec }
+ {
+ german,
+ color-positive = didec-green,
+ color-negative = didec-red,
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_use:n #1
+ {
+ \exp_args:Nf \__didec_format_group:nnn { \didec_to_int:n {#1} }{}{}
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_use_check:n #1
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_use:n { #1 }
+ }
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_color_use:n #1
+ {
+ \color_group_begin:
+ \exp_args:Nf \__didec_format_group:nnn { \didec_to_int:n {#1} }
+ { \color_select:n { didec-positive } }
+ { \color_select:n { didec-negative } }
+ \color_group_end:
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_color_use_check:n #1
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_color_use:n { #1 }
+ }
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_color_inverse_use:n #1
+ {
+ \color_group_begin:
+ \exp_args:Nf \__didec_format_group:nnn { \didec_to_int:n {#1} }
+ { \color_select:n { didec-negative } }
+ { \color_select:n { didec-positive } }
+ \color_group_end:
+ }
+
+% #1 didec variable
+\cs_new:Npn \didec_color_inverse_use_check:n #1
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \didec_color_inverse_use:n { #1 }
+ }
+ }
+
+
+%------- messages -------------------
+
+\msg_new:nnnn { didec }{ already-defined }
+ { Didec~variable~'#1'~already~defined. }
+ { You~tried~to~create~a~new~didec~variable~'#1',~but~it~was~already~defined~elsewhere. }
+
+
+\msg_new:nnnn { didec }{ no-variable }
+ { Unknown~didec~variable~'#1'. }
+ { The~didec~variable~'#1'~you~used~is~unknown. }
+
+
+
+%------- didec user functions -------------------
+
+% #1 didec variable
+\NewExpandableDocumentCommand \didectoint { m }
+ {
+ \exp_args:Ne \didec_to_int_check:n{ \tl_trim_spaces:n { #1 } }
+ }
+
+% #1 didec variable
+\NewExpandableDocumentCommand \didectofp { m }
+ {
+ \exp_args:Ne \didec_to_fp_check:n{ \tl_trim_spaces:n { #1 } }
+ }
+
+% #1 didec variable
+\NewExpandableDocumentCommand \didectofc { m }
+ {
+ \exp_args:Ne \didec_to_fc_check:n{ \tl_trim_spaces:n { #1 } }
+ }
+
+% #1 didec variable
+\NewDocumentCommand \didecnew { m }
+ {
+ \exp_args:Ne \didec_new:n{ \tl_trim_spaces:n { #1 } }
+ }
+\NewCommandCopy \didecnewvar \didecnew
+
+% Sets didec variable #1 to the current value of didec variable #2
+\NewDocumentCommand \didecsetequal { m m }
+ {
+ \exp_args:Nee \didec_gset_eq_check:nn { \tl_trim_spaces:n { #1 } }{ \tl_trim_spaces:n { #2 } }
+ }
+
+% set didec variable #1 to didec expression #2
+% #1 didec variable
+% #2 didec expression
+\NewDocumentCommand \didecset { m m }
+ {
+ \exp_args:Ne \didec_gset_check:nn { \tl_trim_spaces:n { #1 } }{ #2 }
+ }
+
+% set didec variable #1 to didec expression #2
+% #1 didec variable
+% #2 didec expression
+\NewDocumentCommand \didecsetnegative { m m }
+ {
+ \exp_args:Ne \didec_gset_negative_check:nn { \tl_trim_spaces:n { #1 } }{ #2 }
+ }
+
+% set didec variable #1 to floating-point expression #2
+% #1 didec variable
+% #2 floating-point expression
+\NewDocumentCommand \didecsetfp { m m }
+ {
+ \exp_args:Ne \didec_gset_fp_check:nn { \tl_trim_spaces:n { #1 } }{ #2 }
+ }
+
+
+% #1 didec variable
+% #2 didec expression / variable
+% #3 didec expression
+\NewDocumentCommand \didecadd { o m m }
+ {
+ \IfNoValueTF {#1}
+ {
+ \exp_args:Ne \didec_gadd_check:nn { \tl_trim_spaces:n { #2 } }{ #3 }
+ }
+ {
+ \exp_args:Ne \didec_gadd_to_check:nnn { \tl_trim_spaces:n { #1 } }{ #2 }{ #3 }
+ }
+ }
+
+
+% #1 didec variable
+% #2 didec expression / variable
+% #3 didec expression
+\NewDocumentCommand \didecsub { o m m }
+ {
+ \IfNoValueTF {#1}
+ {
+ \exp_args:Ne \didec_gsub_check:nn { \tl_trim_spaces:n { #2 } }{ #3 }
+ }
+ {
+ \exp_args:Ne \didec_gsub_to_check:nnn { \tl_trim_spaces:n { #1 } }{ #2 }{ #3 }
+ }
+ }
+
+% #1 didec variable
+% #2 didec variable
+% #3 floating-point expression
+\NewDocumentCommand \didecmulfp { o m m }
+ {
+ \IfNoValueTF {#1}
+ {
+ \exp_args:Ne \didec_gmul_fp_check:nn { \tl_trim_spaces:n { #2 } }{ #3 }
+ }
+ {
+ \exp_args:Nee \didec_gmul_fp_to_check:nnn { \tl_trim_spaces:n { #1 } }{ \tl_trim_spaces:n { #2 } }{ #3 }
+ }
+ }
+
+% #1 didec variable
+% #2 didec variable
+% #3 floating-point expression
+\NewDocumentCommand \didecdivfp { o m m }
+ {
+ \IfNoValueTF {#1}
+ {
+ \exp_args:Ne \didec_gdiv_fp_check:nn { \tl_trim_spaces:n { #2 } }{ #3 }
+ }
+ {
+ \exp_args:Nee \didec_gdiv_fp_to_check:nnn { \tl_trim_spaces:n { #1 } }{ \tl_trim_spaces:n { #2 } }{ #3 }
+ }
+ }
+
+
+% Deprecated
+\NewDocumentCommand \didecmul { >{\TrimSpaces} O{#2} >{\TrimSpaces} m >{\TrimSpaces} m }
+ {
+ \__didec_gset_int_check:nn { #1 }{ \fp_to_int:n { \__didec_eval:n { #2 } / 100 * \__didec_eval:n { #3 } } }
+ }
+
+
+% Deprecated
+\NewDocumentCommand \didecdiv { >{\TrimSpaces} O{#2} >{\TrimSpaces} m >{\TrimSpaces} m }
+ {
+ \__didec_gset_int_check:nn { #1 }{ \fp_to_int:n { \__didec_eval:n { #2 } / \__didec_eval:n { #3 } * 100 } }
+ }
+
+
+% Deprecated
+\NewDocumentCommand \didecpercent { >{\TrimSpaces} O{#2} >{\TrimSpaces} m >{\TrimSpaces} m }
+ {
+ \__didec_gset_int_check:nn { #1 }{ \fp_to_int:n { \__didec_eval:n { #2 } / \__didec_eval:n { #3 } * 10000 } }
+ }
+
+
+\cs_new:Npn \__didec_sum:w #1#2+#3#4 \q_stop
+ {
+ \exp_args:Nne \didec_gadd:nn { #1 }{ #2 }
+ \quark_if_nil:NF #3
+ {
+ \__didec_sum:w {#1} #3#4 \q_stop
+ }
+ }
+
+\didec_new:n {__@temp@__}
+
+% #1 didec variable
+% #2 sum of didec expressions
+\NewDocumentCommand \didecsetsum { m m }
+ {
+ \__didec_if_exist_else_error:nT { #1 }
+ {
+ \__didec_gset_int:nn {__@temp@__}{ 0 }
+ \__didec_sum:w {__@temp@__} #2 + \q_nil \q_stop
+ \didec_gset_eq:nn { #1 }{__@temp@__}
+ }
+ }
+
+
+% Deprecated
+% #1 type (german,english,float)
+% #2 didec expression
+\NewDocumentCommand \didecprint { O{german} m }
+ {
+ \didecset{__@temp@__}{ #2 }
+ \didecuse [ #1 ]{__@temp@__}
+ }
+
+
+\tl_new:N \g__didec_temp_tl
+
+% Deprecated
+% #1 type (german,english,float)
+% #2 didec expression
+% #3 target macro without backslash
+\NewDocumentCommand \didecstore { O{german} m >{\TrimSpaces}m }
+ {
+ \didecset{__@temp@__}{ #2 }
+ \group_begin:
+ \keys_set:nn { didec }{ #1 }
+ \tl_gset:Ne \g__didec_temp_tl { \didec_use:n { __@temp@__ } }
+ \group_end:
+ \cs_set_eq:cN { #3 } \g__didec_temp_tl
+ }
+
+% #1 key list
+% #2 didec variable
+\NewDocumentCommand \didecuse { o m }
+ {
+ \IfNoValueTF {#1}
+ {
+ \exp_args:Ne \didec_use_check:n { \tl_trim_spaces:n { #2 } }
+ }
+ {
+ \group_begin:
+ \keys_set:nn { didec }{ #1 }
+ \exp_args:Ne \didec_use_check:n { \tl_trim_spaces:n { #2 } }
+ \group_end:
+ }
+ }
+
+% #1 key list
+% #2 didec variable
+\NewDocumentCommand \dideccoluse { o m }
+ {
+ \IfNoValueTF {#1}
+ {
+ \exp_args:Ne \didec_color_use_check:n { \tl_trim_spaces:n { #2 } }
+ }
+ {
+ \group_begin:
+ \keys_set:nn { didec }{ #1 }
+ \exp_args:Ne \didec_color_use_check:n { \tl_trim_spaces:n { #2 } }
+ \group_end:
+ }
+ }
+
+% #1 key list
+% #2 didec variable
+\NewDocumentCommand \dideccolinvuse { o m }
+ {
+ \IfNoValueTF {#1}
+ {
+ \exp_args:Ne \didec_color_inverse_use_check:n { \tl_trim_spaces:n { #2 } }
+ }
+ {
+ \group_begin:
+ \keys_set:nn { didec }{ #1 }
+ \exp_args:Ne \didec_color_inverse_use_check:n { \tl_trim_spaces:n { #2 } }
+ \group_end:
+ }
+ }
+
+% #1 key list
+% #2 didec expression
+\NewDocumentCommand \didecformat { o m }
+ {
+ \didec_gset:nn { __@temp@__ }{ #2 }
+ \IfNoValueTF {#1}
+ {
+ \didec_use:n { __@temp@__ }
+ }
+ {
+ \group_begin:
+ \keys_set:nn { didec }{ #1 }
+ \didec_use:n { __@temp@__ }
+ \group_end:
+ }
+ }
+
+% #1 key list
+% #2 didec expression
+\NewDocumentCommand \dideccolformat { o m }
+ {
+ \didec_gset:nn { __@temp@__ }{ #2 }
+ \IfNoValueTF {#1}
+ {
+ \didec_color_use:n { __@temp@__ }
+ }
+ {
+ \group_begin:
+ \keys_set:nn { didec }{ #1 }
+ \didec_color_use:n { __@temp@__ }
+ \group_end:
+ }
+ }
+
+% #1 key list
+% #2 didec expression
+\NewDocumentCommand \dideccolinvformat { o m }
+ {
+ \didec_gset:nn { __@temp@__ }{ #2 }
+ \IfNoValueTF {#1}
+ {
+ \didec_color_inverse_use:n { __@temp@__ }
+ }
+ {
+ \group_begin:
+ \keys_set:nn { didec }{ #1 }
+ \didec_color_inverse_use:n { __@temp@__ }
+ \group_end:
+ }
+ }
+
+% #1 key list
+\NewDocumentCommand \didecsetup { m }
+ {
+ \keys_set:nn { didec }{ #1 }
+ }
+
+% #1 didec variable
+% #2 stream
+\NewDocumentCommand \didecwrite { m m }
+ {
+ \exp_args:Ne \didec_write_check:nn { \tl_trim_spaces:n { #1 } }{ #2 }
+ }
+
+
+%------- didec conditionals -------------------
+
+% #1 didec variable
+\NewDocumentCommand \didecifnegative { m }
+ {
+ \exp_args:Ne \didec_if_negative:nTF { \tl_trim_spaces:n { #1 } }
+ }
+\NewCommandCopy \didecifnegativ \didecifnegative % Deprecated
+
+% #1 didec variable
+\NewDocumentCommand \didecifpositive { m }
+ {
+ \exp_args:Ne \didec_if_positive:nTF { \tl_trim_spaces:n { #1 } }
+ }
+\NewCommandCopy \didecifpositiv \didecifpositive % Deprecated
+
+% #1 didec variable
+\NewDocumentCommand \didecifzero { m }
+ {
+ \exp_args:Ne \didec_if_zero:nTF { \tl_trim_spaces:n { #1 } }
+ }
+\NewCommandCopy \didecifnull \didecifzero % Deprecated
+
+% #1 didec expression
+% #2 didec expression
+\NewDocumentCommand \dideciflowerthan { m m }
+ {
+ \didec_compare:nNnTF { #1 } < { #2 }
+ }
+
+% #1 didec expression
+% #2 didec expression
+\NewDocumentCommand \didecifequal { m m }
+ {
+ \didec_compare:nNnTF { #1 } = { #2 }
+ }
+
+% #1 didec expression
+% #2 didec expression
+\NewDocumentCommand \didecifgreaterthan { m m }
+ {
+ \didec_compare:nNnTF { #1 } > { #2 }
+ }