Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create to fixed function #551

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions src/gleam/float.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -539,3 +539,162 @@ pub fn multiply(a: Float, b: Float) -> Float {
pub fn subtract(a: Float, b: Float) -> Float {
a -. b
}

/// Converts a float to a string with a fixed number of decimal places.
/// This function is equivalent to number.toFixed in JavaScript.
///
/// ## Examples
///
/// ```gleam
/// to_string_fixed(2.3, 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name in the examples here doesn't match the code.

/// // -> Ok("2")
/// ```
///
/// ```gleam
/// to_string_fixed(0.3, 3)
/// // -> Ok("0.300")
///
/// ```gleam
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these markdown code blocks should be properly closed

/// to_string_fixed(1.5921, 3)
/// // -> Ok("1.592")
pub fn to_fixed_string(x: Float, precision: Int) -> Result(String, Nil) {
let string_representation = to_string(x)

let values = get_float_sides(string_representation)
let left_side = values.0
let right_side = values.1

case precision {
0 -> {
let result_string = slice_string(left_side, 0, -1)
let right_side_number_rounding =
convert_string_to_int(slice_string(right_side, 0, 1))
|> get_int_result_value()

let left_side_last_number =
reverse_string(left_side)
|> slice_string(0, 1)
|> convert_string_to_int()
|> get_int_result_value()

let last_char = case right_side_number_rounding {
number_rounding if number_rounding >= 5 ->
fn(last_char) { last_char + 1 }(left_side_last_number)
_ -> left_side_last_number
}

Ok(append_string(result_string, convert_int_to_string(last_char)))
}
precision if precision > 0 -> {
let result_string =
slice_string(left_side, 0, get_string_length(left_side))
let char_count = get_string_length(right_side)
let updated_right_side = case char_count {
char_count if char_count < precision -> {
pad_string_right(
right_side,
"0",
precision - get_string_length(right_side),
)
}
char_count if char_count == precision -> {
right_side
}

_ -> {
let right_string = slice_string(right_side, 0, precision + 1)
let right_string_length = get_string_length(right_string)

let last_char_before_update =
slice_string(right_string, precision - 1, precision)
|> convert_string_to_int()
|> get_int_result_value()

let char_after_last_char = case right_string_length {
right_string_length if right_string_length > precision -> {
slice_string(right_string, precision, 1)
slice_string(right_string, precision, precision + 1)
|> convert_string_to_int()
|> get_int_result_value()
}
_ -> {
0
}
}

let last_char = case char_after_last_char {
char_after_last_char if char_after_last_char >= 5 -> {
last_char_before_update + 1
}
_ -> {
last_char_before_update
}
}

append_string(
slice_string(right_string, 0, precision - 1),
convert_int_to_string(last_char),
)
}
}
Ok(result_string <> "." <> updated_right_side)
}
_ -> Error(Nil)
}
}

@external(erlang, "gleam_stdlib", "parse_int")
@external(javascript, "../gleam_stdlib.mjs", "parse_int")
fn convert_string_to_int(a: String) -> Result(Int, Nil)

@external(erlang, "erlang", "integer_to_binary")
@external(javascript, "../gleam_stdlib.mjs", "to_string")
fn convert_int_to_string(a: Int) -> String

@external(erlang, "string", "length")
@external(javascript, "../gleam_stdlib.mjs", "string_length")
fn get_string_length(a: String) -> Int

@external(erlang, "string", "split")
@external(javascript, "../gleam_stdlib.mjs", "split")
fn split_string(value: String, separator: String) -> List(String)

@external(erlang, "string", "slice")
@external(javascript, "../gleam_stdlib.mjs", "string_slice")
fn slice_string(value: String, start: Int, end: Int) -> String

@external(javascript, "../gleam_stdlib.mjs", "string_reverse")
fn reverse_string(value: String) -> String

fn append_string(a: String, b: String) -> String {
a <> b
}

fn pad_string_right(value: String, character: String, difference: Int) -> String {
case difference > 0 {
True -> {
case difference {
difference if difference > 0 -> {
append_string(value, character)
|> pad_string_right(character, difference - 1)
}
_ -> value
}
}
False -> value
}
}

pub fn get_float_sides(value: String) -> #(String, String) {
case split_string(value, ".") {
[left_side, right_side] -> #(left_side, right_side)
_ -> #("", "")
}
}

fn get_int_result_value(result: Result(Int, Nil)) -> Int {
case result {
Ok(v) -> v
Error(_) -> 0
}
}
5 changes: 5 additions & 0 deletions src/gleam_stdlib.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ export function string_replace(string, target, substitute) {
);
}

export function string_slice(string, start, end) {
return string.slice(start, end);
}


export function string_reverse(string) {
return [...string].reverse().join("");
}
Expand Down
19 changes: 19 additions & 0 deletions test/gleam/float_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import gleam/iterator
import gleam/list
import gleam/order
import gleam/should
import gleam/result

pub fn parse_test() {
"1.23"
Expand Down Expand Up @@ -413,3 +414,21 @@ pub fn subtract_test() {
|> float.subtract(2.0, _)
|> should.equal(-1.0)
}

pub fn to_fixed_string_test() {
float.to_fixed_string(1.2345, 3)
|> result.unwrap("")
|> should.equal("1.235")

float.to_fixed_string(1.9283472389479283478, 8)
|> result.unwrap("")
|> should.equal("1.92834724")

float.to_fixed_string(0.98, 0)
|> result.unwrap("")
|> should.equal("1")

float.to_fixed_string(55.01, 5)
|> result.unwrap("")
|> should.equal("55.01000")
}