diff options
Diffstat (limited to 'macros/latex/contrib/didec/didec.sty')
-rw-r--r-- | macros/latex/contrib/didec/didec.sty | 1349 |
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 } + } |