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