ublog

зберігаємо, працюємо з балансом користувача

programming [35]erlang [33]postgresql [9]


зберігаємо та працюємо з балансом користувача,
в erlang та postgresql


Як ви можете знати, використання float -- числа з плаваючою комою,
неминуче приводить до похибок арифметики та округлень.
https://uk.wikipedia.org/wiki/IEEE_754
https://habrahabr.ru/post/309812/
Відповідно для зберігання грошей на балансі користувача float не підходить.

На мою думку, баланс користувача краще зберігати в integer, в копійках
CREATE TABLE "test_user_balance" (
  "user_id" bigint NOT NULL,
  "balance" bigint NOT NULL,
  PRIMARY KEY ("user_id")
);
INSERT INTO "test_user_balance" ("user_id", "balance") VALUES (1, 1000);
-- user_id = 1, balance = 1000 = $10


декілька функцій для роботи зі значеннями
%575 -> <<"5.75">>
balance_int2bin(V) ->
  if V =:= 0 ->
      <<"0.00">>;
    V =:= 100 ->
      <<"1.00">>;
    V < 100 ->
      erlang:list_to_binary("0." ++ erlang:integer_to_list(V));
    V > 100 ->
      V0 = erlang:integer_to_list(V),
      VL = erlang:length(V0) - 2,
      erlang:list_to_binary(string:sub_string(V0,1,VL) ++ "." ++ string:sub_string(V0,VL+1))
  end.


%"5.45" -> 545
%"5" -> 500
%<<"5.45">> -> 545
%<<"5">> -> 500
input_balance2int(V) when erlang:is_list(V) ->
  %list string
  [R1|T] = string:split(V,"."),
  case T =:= [] of
    true ->
      erlang:list_to_integer(R1) * 100;
    _ ->
      [R2|_] = T,
      erlang:list_to_integer(R1) * 100 + erlang:list_to_integer(R2)
  end;
input_balance2int(V) when erlang:is_binary(V) ->
  %binary string
  [R1|T] = binary:split(V, <<".">>),
  case T =:= [] of
    true ->
      erlang:binary_to_integer(R1) * 100;
    _ ->
      [R2|_] = T,
      erlang:binary_to_integer(R1) * 100 + erlang:binary_to_integer(R2)
  end.


деякі гуру програмування можуть сказати "фу, цей код треба причесати-відрефакторити"
можливо, вони праві :)

з іншої сторони -- "працює -- значить не лайно" :)
далі буде...