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 "platform.h"
23 : #include "taler_json_lib.h"
24 : #include <gnunet/gnunet_curl_lib.h>
25 : #include "exchange_api_handle.h"
26 :
27 :
28 : /**
29 : * Check if @a a and @a b are numerically close.
30 : *
31 : * @param a an amount
32 : * @param b an amount
33 : * @return true if both values are quite close
34 : */
35 : static bool
36 35448 : amount_close (const struct TALER_Amount *a,
37 : const struct TALER_Amount *b)
38 : {
39 : struct TALER_Amount delta;
40 :
41 35448 : switch (TALER_amount_cmp (a,
42 : b))
43 : {
44 0 : case -1: /* a < b */
45 0 : GNUNET_assert (0 <
46 : TALER_amount_subtract (&delta,
47 : b,
48 : a));
49 0 : break;
50 18912 : case 0:
51 : /* perfect */
52 18912 : return true;
53 16536 : case 1: /* a > b */
54 16536 : GNUNET_assert (0 <
55 : TALER_amount_subtract (&delta,
56 : a,
57 : b));
58 16536 : break;
59 : }
60 16536 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
61 : "Rounding error is %s\n",
62 : TALER_amount2s (&delta));
63 16536 : if (delta.value > 0)
64 : {
65 0 : GNUNET_break (0);
66 0 : return false;
67 : }
68 16536 : if (delta.fraction > 5000)
69 : {
70 0 : GNUNET_break (0);
71 0 : return false;
72 : }
73 16536 : return true; /* let's consider this a rounding error */
74 : }
75 :
76 :
77 : int
78 1 : main (int argc,
79 : char **argv)
80 : {
81 : struct TALER_EXCHANGE_DenomPublicKey dk;
82 1 : struct TALER_EXCHANGE_Keys keys = {
83 : .denom_keys = &dk,
84 : .num_denom_keys = 1
85 : };
86 : struct TALER_Amount brut;
87 : struct TALER_Amount net;
88 :
89 : (void) argc;
90 : (void) argv;
91 1 : GNUNET_log_setup ("test-stefan",
92 : "INFO",
93 : NULL);
94 1 : GNUNET_assert (GNUNET_OK ==
95 : TALER_string_to_amount ("MAGIC:0.00001",
96 : &dk.value));
97 1 : GNUNET_assert (GNUNET_OK ==
98 : TALER_string_to_amount ("MAGIC:1",
99 : &keys.stefan_abs));
100 1 : GNUNET_assert (GNUNET_OK ==
101 : TALER_string_to_amount ("MAGIC:0.13",
102 : &keys.stefan_log));
103 1 : keys.stefan_lin = 1.15;
104 1 : GNUNET_assert (GNUNET_OK ==
105 : TALER_string_to_amount ("MAGIC:4",
106 : &brut));
107 1 : GNUNET_log_skip (1,
108 : GNUNET_NO);
109 1 : GNUNET_assert (GNUNET_SYSERR ==
110 : TALER_EXCHANGE_keys_stefan_b2n (&keys,
111 : &brut,
112 : &net));
113 1 : GNUNET_assert (GNUNET_OK ==
114 : TALER_string_to_amount ("MAGIC:4",
115 : &net));
116 1 : GNUNET_log_skip (1,
117 : GNUNET_NO);
118 1 : GNUNET_assert (GNUNET_SYSERR ==
119 : TALER_EXCHANGE_keys_stefan_n2b (&keys,
120 : &net,
121 : &brut));
122 1 : keys.stefan_lin = 1.0;
123 1 : GNUNET_assert (GNUNET_OK ==
124 : TALER_string_to_amount ("MAGIC:4",
125 : &brut));
126 1 : GNUNET_log_skip (1,
127 : GNUNET_NO);
128 1 : GNUNET_assert (GNUNET_SYSERR ==
129 : TALER_EXCHANGE_keys_stefan_b2n (&keys,
130 : &brut,
131 : &net));
132 1 : GNUNET_assert (GNUNET_OK ==
133 : TALER_string_to_amount ("MAGIC:4",
134 : &net));
135 1 : GNUNET_log_skip (1,
136 : GNUNET_NO);
137 1 : GNUNET_assert (GNUNET_SYSERR ==
138 : TALER_EXCHANGE_keys_stefan_n2b (&keys,
139 : &net,
140 : &brut));
141 1 : GNUNET_assert (0 == GNUNET_get_log_skip ());
142 1 : keys.stefan_lin = 0.1;
143 :
144 : /* try various values for lin and log STEFAN values */
145 13 : for (unsigned int li = 1; li < 13; li += 1)
146 : {
147 12 : keys.stefan_lin = 1.0 * li / 100.0;
148 :
149 1200 : for (unsigned int lx = 1; lx < 100; lx += 1)
150 : {
151 1188 : keys.stefan_log.fraction = lx * TALER_AMOUNT_FRAC_BASE / 100;
152 :
153 : /* Check brutto-to-netto is stable */
154 13068 : for (unsigned int i = 0; i<10; i++)
155 : {
156 : struct TALER_Amount rval;
157 :
158 11880 : brut.value = i;
159 11880 : brut.fraction = i * TALER_AMOUNT_FRAC_BASE / 10;
160 11880 : GNUNET_assert (GNUNET_SYSERR !=
161 : TALER_EXCHANGE_keys_stefan_b2n (&keys,
162 : &brut,
163 : &net));
164 11880 : GNUNET_assert (GNUNET_SYSERR !=
165 : TALER_EXCHANGE_keys_stefan_n2b (&keys,
166 : &net,
167 : &rval));
168 11880 : if (TALER_amount_is_zero (&net))
169 6036 : GNUNET_assert (TALER_amount_is_zero (&rval));
170 : else
171 : {
172 5844 : GNUNET_assert (amount_close (&brut,
173 : &rval));
174 5844 : TALER_EXCHANGE_keys_stefan_round (&keys,
175 : &rval);
176 5844 : GNUNET_assert (amount_close (&brut,
177 : &rval));
178 : }
179 : }
180 :
181 : /* Check netto-to-brutto is stable */
182 13068 : for (unsigned int i = 0; i<10; i++)
183 : {
184 : struct TALER_Amount rval;
185 :
186 11880 : net.value = i;
187 11880 : net.fraction = i * TALER_AMOUNT_FRAC_BASE / 10;
188 11880 : GNUNET_assert (GNUNET_SYSERR !=
189 : TALER_EXCHANGE_keys_stefan_n2b (&keys,
190 : &net,
191 : &brut));
192 11880 : GNUNET_assert (GNUNET_SYSERR !=
193 : TALER_EXCHANGE_keys_stefan_b2n (&keys,
194 : &brut,
195 : &rval));
196 11880 : GNUNET_assert (amount_close (&net,
197 : &rval));
198 11880 : TALER_EXCHANGE_keys_stefan_round (&keys,
199 : &rval);
200 11880 : GNUNET_assert (amount_close (&net,
201 : &rval));
202 : }
203 : }
204 : }
205 1 : return 0;
206 : }
|