Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2023 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see
15 : <http://www.gnu.org/licenses/>
16 : */
17 : /**
18 : * @file lib/test_stefan.c
19 : * @brief test calculations on the STEFAN curve
20 : * @author Christian Grothoff
21 : */
22 : #include "taler/taler_json_lib.h"
23 : #include <gnunet/gnunet_curl_lib.h>
24 : #include "exchange_api_handle.h"
25 :
26 :
27 : /**
28 : * Check if @a a and @a b are numerically close.
29 : *
30 : * @param a an amount
31 : * @param b an amount
32 : * @return true if both values are quite close
33 : */
34 : static bool
35 35448 : amount_close (const struct TALER_Amount *a,
36 : const struct TALER_Amount *b)
37 : {
38 : struct TALER_Amount delta;
39 :
40 35448 : switch (TALER_amount_cmp (a,
41 : b))
42 : {
43 0 : case -1: /* a < b */
44 0 : GNUNET_assert (0 <
45 : TALER_amount_subtract (&delta,
46 : b,
47 : a));
48 0 : break;
49 18912 : case 0:
50 : /* perfect */
51 18912 : return true;
52 16536 : case 1: /* a > b */
53 16536 : GNUNET_assert (0 <
54 : TALER_amount_subtract (&delta,
55 : a,
56 : b));
57 16536 : break;
58 : }
59 16536 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
60 : "Rounding error is %s\n",
61 : TALER_amount2s (&delta));
62 16536 : if (delta.value > 0)
63 : {
64 0 : GNUNET_break (0);
65 0 : return false;
66 : }
67 16536 : if (delta.fraction > 5000)
68 : {
69 0 : GNUNET_break (0);
70 0 : return false;
71 : }
72 16536 : return true; /* let's consider this a rounding error */
73 : }
74 :
75 :
76 : int
77 1 : main (int argc,
78 : char **argv)
79 : {
80 : struct TALER_EXCHANGE_DenomPublicKey dk;
81 1 : struct TALER_EXCHANGE_Keys keys = {
82 : .denom_keys = &dk,
83 : .num_denom_keys = 1
84 : };
85 : struct TALER_Amount brut;
86 : struct TALER_Amount net;
87 :
88 : (void) argc;
89 : (void) argv;
90 1 : GNUNET_log_setup ("test-stefan",
91 : "INFO",
92 : NULL);
93 1 : GNUNET_assert (GNUNET_OK ==
94 : TALER_string_to_amount ("MAGIC:0.00001",
95 : &dk.value));
96 1 : GNUNET_assert (GNUNET_OK ==
97 : TALER_string_to_amount ("MAGIC:1",
98 : &keys.stefan_abs));
99 1 : GNUNET_assert (GNUNET_OK ==
100 : TALER_string_to_amount ("MAGIC:0.13",
101 : &keys.stefan_log));
102 1 : keys.stefan_lin = 1.15;
103 1 : GNUNET_assert (GNUNET_OK ==
104 : TALER_string_to_amount ("MAGIC:4",
105 : &brut));
106 1 : GNUNET_log_skip (1,
107 : GNUNET_NO);
108 1 : GNUNET_assert (GNUNET_SYSERR ==
109 : TALER_EXCHANGE_keys_stefan_b2n (&keys,
110 : &brut,
111 : &net));
112 1 : GNUNET_assert (GNUNET_OK ==
113 : TALER_string_to_amount ("MAGIC:4",
114 : &net));
115 1 : GNUNET_log_skip (1,
116 : GNUNET_NO);
117 1 : GNUNET_assert (GNUNET_SYSERR ==
118 : TALER_EXCHANGE_keys_stefan_n2b (&keys,
119 : &net,
120 : &brut));
121 1 : keys.stefan_lin = 1.0;
122 1 : GNUNET_assert (GNUNET_OK ==
123 : TALER_string_to_amount ("MAGIC:4",
124 : &brut));
125 1 : GNUNET_log_skip (1,
126 : GNUNET_NO);
127 1 : GNUNET_assert (GNUNET_SYSERR ==
128 : TALER_EXCHANGE_keys_stefan_b2n (&keys,
129 : &brut,
130 : &net));
131 1 : GNUNET_assert (GNUNET_OK ==
132 : TALER_string_to_amount ("MAGIC:4",
133 : &net));
134 1 : GNUNET_log_skip (1,
135 : GNUNET_NO);
136 1 : GNUNET_assert (GNUNET_SYSERR ==
137 : TALER_EXCHANGE_keys_stefan_n2b (&keys,
138 : &net,
139 : &brut));
140 1 : GNUNET_assert (0 == GNUNET_get_log_skip ());
141 1 : keys.stefan_lin = 0.1;
142 :
143 : /* try various values for lin and log STEFAN values */
144 13 : for (unsigned int li = 1; li < 13; li += 1)
145 : {
146 12 : keys.stefan_lin = 1.0 * li / 100.0;
147 :
148 1200 : for (unsigned int lx = 1; lx < 100; lx += 1)
149 : {
150 1188 : keys.stefan_log.fraction = lx * TALER_AMOUNT_FRAC_BASE / 100;
151 :
152 : /* Check brutto-to-netto is stable */
153 13068 : for (unsigned int i = 0; i<10; i++)
154 : {
155 : struct TALER_Amount rval;
156 :
157 11880 : brut.value = i;
158 11880 : brut.fraction = i * TALER_AMOUNT_FRAC_BASE / 10;
159 11880 : GNUNET_assert (GNUNET_SYSERR !=
160 : TALER_EXCHANGE_keys_stefan_b2n (&keys,
161 : &brut,
162 : &net));
163 11880 : GNUNET_assert (GNUNET_SYSERR !=
164 : TALER_EXCHANGE_keys_stefan_n2b (&keys,
165 : &net,
166 : &rval));
167 11880 : if (TALER_amount_is_zero (&net))
168 6036 : GNUNET_assert (TALER_amount_is_zero (&rval));
169 : else
170 : {
171 5844 : GNUNET_assert (amount_close (&brut,
172 : &rval));
173 5844 : TALER_EXCHANGE_keys_stefan_round (&keys,
174 : &rval);
175 5844 : GNUNET_assert (amount_close (&brut,
176 : &rval));
177 : }
178 : }
179 :
180 : /* Check netto-to-brutto is stable */
181 13068 : for (unsigned int i = 0; i<10; i++)
182 : {
183 : struct TALER_Amount rval;
184 :
185 11880 : net.value = i;
186 11880 : net.fraction = i * TALER_AMOUNT_FRAC_BASE / 10;
187 11880 : GNUNET_assert (GNUNET_SYSERR !=
188 : TALER_EXCHANGE_keys_stefan_n2b (&keys,
189 : &net,
190 : &brut));
191 11880 : GNUNET_assert (GNUNET_SYSERR !=
192 : TALER_EXCHANGE_keys_stefan_b2n (&keys,
193 : &brut,
194 : &rval));
195 11880 : GNUNET_assert (amount_close (&net,
196 : &rval));
197 11880 : TALER_EXCHANGE_keys_stefan_round (&keys,
198 : &rval);
199 11880 : GNUNET_assert (amount_close (&net,
200 : &rval));
201 : }
202 : }
203 : }
204 1 : return 0;
205 : }
|