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