%% 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 %% ------------------------------------------------------------------------------------------- %% %% 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 } % % 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: } % % #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: } % % #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: } % % #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: } % % #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: } % % #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: } % % #1 didec variable \cs_new:Npn \didec_to_int:n #1 { \int_use:c { g_didec_var_#1_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 } } } % % 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 } } % % 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 } } % % 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 } % % 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: } % % #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: } } % % #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: } } % % #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 } } } } % % #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: } } } % % #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: } } % % #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: } } % % #1 didec variable \cs_new:Npn \didec_to_int:n #1 { \fp_use:c { g_didec_var_#1_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 } } } % % 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 } } % % 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 } } % % 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 } }