amount rounding a la Christian
This commit is contained in:
parent
ac2e40d049
commit
7378b5a081
@ -88,7 +88,7 @@ static char *currency;
|
|||||||
/**
|
/**
|
||||||
* How many fractional digits does the currency use?
|
* How many fractional digits does the currency use?
|
||||||
*/
|
*/
|
||||||
static uint8_t currency_rounding_fractional_digits;
|
static struct TALER_Amount currency_round_unit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our configuration.
|
* Our configuration.
|
||||||
@ -2894,7 +2894,7 @@ check_wire_out_cb
|
|||||||
|
|
||||||
/* Round down to amount supported by wire method */
|
/* Round down to amount supported by wire method */
|
||||||
GNUNET_break (TALER_amount_round_down (&final_amount,
|
GNUNET_break (TALER_amount_round_down (&final_amount,
|
||||||
currency_rounding_fractional_digits));
|
¤cy_round_unit));
|
||||||
|
|
||||||
/* Calculate the exchange's gain as the fees plus rounding differences! */
|
/* Calculate the exchange's gain as the fees plus rounding differences! */
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
@ -5205,28 +5205,29 @@ run (void *cls,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
unsigned long long num;
|
char *rounding_str;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONFIGURATION_get_value_number (cfg,
|
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||||
"taler",
|
"taler",
|
||||||
"CURRENCY_ROUNDING_FRACTIONAL_DIGITS",
|
"CURRENCY_ROUND_UNIT",
|
||||||
&num))
|
&rounding_str))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
"No [taler]/CURRENCY_ROUNDING_FRACTIONAL_DIGITS specified, defaulting to 2 digits.\n");
|
"No [taler]/CURRENCY_ROUND_UNIT specified, defaulting to '0.01'.\n");
|
||||||
currency_rounding_fractional_digits = 2;
|
TALER_amount_get_zero (currency, ¤cy_round_unit);
|
||||||
|
currency_round_unit.fraction = TALER_AMOUNT_FRAC_BASE / 100;
|
||||||
}
|
}
|
||||||
else if (num > TALER_AMOUNT_FRAC_LEN)
|
else if (GNUNET_OK !=
|
||||||
|
TALER_string_to_amount (rounding_str,
|
||||||
|
¤cy_round_unit))
|
||||||
{
|
{
|
||||||
global_ret = 1;
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Value of CURRENCY_ROUNDING_FRACTIONAL_DIGITS too big.\n");
|
"Invalid amount `%s' specified in `TALER' under `CURRENCY_ROUND_UNIT'\n",
|
||||||
|
rounding_str);
|
||||||
|
GNUNET_free (rounding_str);
|
||||||
|
global_ret = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
currency_rounding_fractional_digits = (uint8_t) num;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONFIGURATION_get_value_time (cfg,
|
GNUNET_CONFIGURATION_get_value_time (cfg,
|
||||||
|
@ -224,7 +224,7 @@ static char *exchange_currency_string;
|
|||||||
/**
|
/**
|
||||||
* How many fractional digits does the currency use?
|
* How many fractional digits does the currency use?
|
||||||
*/
|
*/
|
||||||
static uint8_t currency_rounding_fractional_digits;
|
static struct TALER_Amount currency_round_unit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What is the base URL of this exchange?
|
* What is the base URL of this exchange?
|
||||||
@ -615,29 +615,31 @@ exchange_serve_process_config ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
unsigned long long num;
|
char *rounding_str;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONFIGURATION_get_value_number (cfg,
|
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||||
"taler",
|
"taler",
|
||||||
"CURRENCY_ROUNDING_FRACTIONAL_DIGITS",
|
"CURRENCY_ROUND_UNIT",
|
||||||
&num))
|
&rounding_str))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
"No [taler]/CURRENCY_ROUNDING_FRACTIONAL_DIGITS specified, defaulting to 2 digits.\n");
|
"No [taler]/CURRENCY_ROUND_UNIT specified, defaulting to '0.01'.\n");
|
||||||
currency_rounding_fractional_digits = 2;
|
TALER_amount_get_zero (exchange_currency_string, ¤cy_round_unit);
|
||||||
|
currency_round_unit.fraction = TALER_AMOUNT_FRAC_BASE / 100;
|
||||||
}
|
}
|
||||||
else if (num > TALER_AMOUNT_FRAC_LEN)
|
else if (GNUNET_OK !=
|
||||||
|
TALER_string_to_amount (rounding_str,
|
||||||
|
¤cy_round_unit))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Value of CURRENCY_ROUNDING_FRACTIONAL_DIGITS too big.\n");
|
"Invalid amount `%s' specified in `TALER' under `CURRENCY_ROUND_UNIT'\n",
|
||||||
|
rounding_str);
|
||||||
|
GNUNET_free (rounding_str);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
currency_rounding_fractional_digits = (uint8_t) num;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (NULL ==
|
if (NULL ==
|
||||||
(db_plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
|
(db_plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
|
||||||
{
|
{
|
||||||
@ -1120,7 +1122,7 @@ expired_reserve_cb (void *cls,
|
|||||||
/* round down to enable transfer */
|
/* round down to enable transfer */
|
||||||
if (GNUNET_SYSERR ==
|
if (GNUNET_SYSERR ==
|
||||||
TALER_amount_round_down (&amount_without_fee,
|
TALER_amount_round_down (&amount_without_fee,
|
||||||
currency_rounding_fractional_digits))
|
¤cy_round_unit))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
global_ret = GNUNET_SYSERR;
|
global_ret = GNUNET_SYSERR;
|
||||||
@ -1456,7 +1458,7 @@ run_aggregation (void *cls)
|
|||||||
&au->wire_fee)) ||
|
&au->wire_fee)) ||
|
||||||
(GNUNET_SYSERR ==
|
(GNUNET_SYSERR ==
|
||||||
TALER_amount_round_down (&au->final_amount,
|
TALER_amount_round_down (&au->final_amount,
|
||||||
currency_rounding_fractional_digits)) ||
|
¤cy_round_unit)) ||
|
||||||
( (0 == au->final_amount.value) &&
|
( (0 == au->final_amount.value) &&
|
||||||
(0 == au->final_amount.fraction) ) )
|
(0 == au->final_amount.fraction) ) )
|
||||||
{
|
{
|
||||||
|
@ -311,15 +311,18 @@ TALER_amount2s (const struct TALER_Amount *amount);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Round the amount to something that can be transferred on the wire.
|
* Round the amount to something that can be transferred on the wire.
|
||||||
|
* The rounding mode is specified via the smallest transferable unit,
|
||||||
|
* which must only have a fractional part.
|
||||||
*
|
*
|
||||||
* @param[in,out] amount amount to round down
|
* @param[in,out] amount amount to round down
|
||||||
* @param max_fractional_digits number of fractional digits to round down to
|
* @param[in] round_unit unit that should be rounded down to,
|
||||||
|
* the value part of this amount must be zero
|
||||||
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
|
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
|
||||||
* #GNUNET_SYSERR if the amount or currency was invalid
|
* #GNUNET_SYSERR if the amount or currency was invalid
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
TALER_amount_round_down (struct TALER_Amount *amount,
|
TALER_amount_round_down (struct TALER_Amount *amount,
|
||||||
uint8_t max_fractional_digits);
|
const struct TALER_Amount *round_unit);
|
||||||
|
|
||||||
|
|
||||||
#if 0 /* keep Emacsens' auto-indent happy */
|
#if 0 /* keep Emacsens' auto-indent happy */
|
||||||
|
@ -674,23 +674,27 @@ TALER_amount_divide (struct TALER_Amount *result,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Round the amount to something that can be transferred on the wire.
|
* Round the amount to something that can be transferred on the wire.
|
||||||
|
* The rounding mode is specified via the smallest transferable unit,
|
||||||
|
* which must only have a fractional part.
|
||||||
*
|
*
|
||||||
* @param[in,out] amount amount to round down
|
* @param[in,out] amount amount to round down
|
||||||
* @param max_fractional_digits number of fractional digits to round down to
|
* @param[in] round_unit unit that should be rounded down to,
|
||||||
|
* the value part of this amount must be zero
|
||||||
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
|
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
|
||||||
* #GNUNET_SYSERR if the amount or currency was invalid
|
* #GNUNET_SYSERR if the amount or currency was invalid
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
TALER_amount_round_down (struct TALER_Amount *amount,
|
TALER_amount_round_down (struct TALER_Amount *amount,
|
||||||
uint8_t max_fractional_digits)
|
const struct TALER_Amount *round_unit)
|
||||||
{
|
{
|
||||||
uint32_t delta;
|
uint32_t delta;
|
||||||
uint32_t divisor = 1;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < max_fractional_digits; i++)
|
GNUNET_break (0 == round_unit->value);
|
||||||
divisor *= 10;
|
|
||||||
|
|
||||||
delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / divisor);
|
if (0 == round_unit->fraction)
|
||||||
|
return GNUNET_OK;
|
||||||
|
|
||||||
|
delta = amount->fraction % round_unit->fraction;
|
||||||
if (0 == delta)
|
if (0 == delta)
|
||||||
return GNUNET_NO;
|
return GNUNET_NO;
|
||||||
amount->fraction -= delta;
|
amount->fraction -= delta;
|
||||||
|
@ -31,6 +31,7 @@ main (int argc,
|
|||||||
struct TALER_Amount a1;
|
struct TALER_Amount a1;
|
||||||
struct TALER_Amount a2;
|
struct TALER_Amount a2;
|
||||||
struct TALER_Amount a3;
|
struct TALER_Amount a3;
|
||||||
|
struct TALER_Amount r;
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
GNUNET_log_setup ("test-amout",
|
GNUNET_log_setup ("test-amout",
|
||||||
@ -236,6 +237,10 @@ main (int argc,
|
|||||||
|
|
||||||
/* test rounding #1 */
|
/* test rounding #1 */
|
||||||
|
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_string_to_amount ("EUR:0.01",
|
||||||
|
&r));
|
||||||
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
GNUNET_assert (GNUNET_OK ==
|
||||||
TALER_string_to_amount ("EUR:4.001",
|
TALER_string_to_amount ("EUR:4.001",
|
||||||
&a1));
|
&a1));
|
||||||
@ -243,19 +248,23 @@ main (int argc,
|
|||||||
TALER_string_to_amount ("EUR:4",
|
TALER_string_to_amount ("EUR:4",
|
||||||
&a2));
|
&a2));
|
||||||
|
|
||||||
GNUNET_assert (GNUNET_OK == TALER_amount_round_down (&a1, 2));
|
GNUNET_assert (GNUNET_OK == TALER_amount_round_down (&a1, &r));
|
||||||
GNUNET_assert (GNUNET_NO == TALER_amount_round_down (&a1, 2));
|
GNUNET_assert (GNUNET_NO == TALER_amount_round_down (&a1, &r));
|
||||||
GNUNET_assert (0 == TALER_amount_cmp (&a1, &a2));
|
GNUNET_assert (0 == TALER_amount_cmp (&a1, &a2));
|
||||||
|
|
||||||
/* test rounding #2 */
|
/* test rounding #2 */
|
||||||
|
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_string_to_amount ("EUR:0.001",
|
||||||
|
&r));
|
||||||
|
|
||||||
GNUNET_assert (GNUNET_OK ==
|
GNUNET_assert (GNUNET_OK ==
|
||||||
TALER_string_to_amount ("EUR:4.001",
|
TALER_string_to_amount ("EUR:4.001",
|
||||||
&a1));
|
&a1));
|
||||||
GNUNET_assert (GNUNET_OK ==
|
GNUNET_assert (GNUNET_OK ==
|
||||||
TALER_string_to_amount ("EUR:4.001",
|
TALER_string_to_amount ("EUR:4.001",
|
||||||
&a2));
|
&a2));
|
||||||
GNUNET_assert (GNUNET_NO == TALER_amount_round_down (&a1, 3));
|
GNUNET_assert (GNUNET_NO == TALER_amount_round_down (&a1, &r));
|
||||||
GNUNET_assert (0 == TALER_amount_cmp (&a1, &a2));
|
GNUNET_assert (0 == TALER_amount_cmp (&a1, &a2));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user