3

I would like:

unknown_function(123.456) -> 456
unknown_function(1234.56) -> 56

Or

unknown_function(123.456) -> "456"

Is there a builtin for this? The builtin trunc/1 does the opposite:

2> trunc(123.456).
123

There is this answer for C: Extract decimal part from a floating point number in C and this for Java: How to get the decimal part of a float?

Tommy
  • 12,588
  • 14
  • 59
  • 110
  • The links you've posted return the decimal part as a float value. Is that what you want? `N = 123.456, N - trunc(N). => 0.45600000000000307` – Dogbert May 25 '17 at 17:55
  • I want it as an integer, or a string, but not as a float. The accepted answer in the C one was not what the OP asked for, they clarified in comments. No that is not what want. – Tommy May 25 '17 at 17:58
  • This is one way but you'll need to set the number of decimal places you want: `lists:nth(2, string:tokens(float_to_list(123.456, [{decimals, 20}]), ".")).` – Dogbert May 25 '17 at 18:00
  • @Dogbert that seems to introduce rounding errors first, I wonder if there is a way to avoid that, that produces "45600000000000306954" – Tommy May 25 '17 at 18:03
  • @Dogbert I think I can use what you have to make a good answer, will post – Tommy May 25 '17 at 18:20

3 Answers3

2

No there is no BIF for this, but you can do this:

decimal_point(X, DecimalDigits) when X < 0 ->
  decimal_point(-X, DecimalDigits);
decimal_point(X, DecimalDigits)->
  (X - trunc(X)) * math:pow(10,DecimalDigits).

> decimal_point(2.33, 2).
33
> decimal_point(-2.33, 2).
33
Aus
  • 1,183
  • 11
  • 27
0

This is inspired by @Dogbert's comment

The algorithm doesnt work using native floats due to floating point representation limits and rounding errors.

However, using https://github.com/tim/erlang-decimal:

frac_to_denom_int(Num, Denom, Precison) ->
{X, _} = string:to_integer(lists:nth(2, string:tokens(decimal:format(decimal:divide(Num, Denom, [{precision, Precison}])), "."))),
X.

E.g.,

frac_to_denom_int("1.0", "3.0", 1000).
> 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333

If you don't have a frac,

d_to_denom_int(D_Tup)->
    string:to_integer(lists:nth(2, string:tokens(decimal:format(D_Tup), "."))).

d_to_denom_int({0, 123456, -3}).
 > 456
Tommy
  • 12,588
  • 14
  • 59
  • 110
0

Based on @dogbert's comment, passing in one more flag compact on the float_to_list/2 call will help:

lists:nth(2, string:tokens(float_to_list(123.456, [{decimals, 10}, compact]), ".")).
% "456"

If you go over decimals 14, you'll start to see those rounding errors.

Máté
  • 2,294
  • 3
  • 18
  • 25