Skip to content

/commands/ruby/round-float-two-decimals

ruby round a float to 2 decimal places (round, format, BigDecimal)

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
Ruby
versions
Ruby 2.4+ (half: option), Ruby 3.4
os
any

3.14159.round(2) rounds a Float to two decimal places and returns a Float (3.14). To display a number with exactly two decimals, including trailing zeros, use format("%.2f", x), which returns a String such as "5.00". For money and other values where exact decimal arithmetic matters, use BigDecimal or integer cents instead of Float.

Rounding vs formatting

The example runs CRuby 3.4 compiled to WebAssembly (ruby.wasm, the official Ruby project build) with Node.js:

bash
npm init -y >/dev/null
npm install --silent --no-audit --no-fund @ruby/3.4-wasm-wasi@2.8.1 @ruby/wasm-wasi@2.8.1 >/dev/null 2>&1
cat > ruby.mjs <<'EOF'
import fs from "node:fs/promises";
import { DefaultRubyVM } from "@ruby/wasm-wasi/dist/node";
const wasm = await WebAssembly.compile(await fs.readFile("node_modules/@ruby/3.4-wasm-wasi/dist/ruby+stdlib.wasm"));
const { vm } = await DefaultRubyVM(wasm);
vm.eval(await fs.readFile(process.argv[2], "utf8") + "\n$stdout.flush");
EOF
cat > round.rb <<'EOF'
p 3.14159.round(2)
p 5.0.round(2)
p format("%.2f", 5.0)
p "%.2f" % 1234.5
p 2.5.round, 3.5.round
p 2.5.round(half: :even), 2.5.round(half: :down)
p 2.675.round(2)
p 3.149.floor(2), 3.141.ceil(2)
p 1234.5678.round(-2)
p (0.1 + 0.2)
p (0.1 + 0.2).round(2)
[-> { "3.14159".round(2) }, -> { 3.14159.round("2") }, -> { 3.14159.round(2, :even) }].each do |f|
  f.call
rescue => e
  puts "#{e.class}: #{e.message}"
end
EOF
node --no-warnings ruby.mjs round.rb

Output

3.14
5.0
"5.00"
"1234.50"
3
4
2
2
2.68
3.14
3.15
1200
0.30000000000000004
0.3
NoMethodError: undefined method 'round' for an instance of String
TypeError: no implicit conversion of String into Integer
ArgumentError: wrong number of arguments (given 2, expected 0..1)

round drops trailing zeros because it returns a number (5.0), while format returns a String with exactly the digits requested. By default .5 rounds away from zero (2.5.round is 3); half: :even (banker's rounding) and half: :down change that. The three error lines at the end come from the pitfalls listed below.

Methods

CodeReturnsNotes
x.round(2)FloatRound half away from zero by default
x.round(2, half: :even)FloatBanker's rounding (Ruby 2.4+)
x.floor(2) / x.ceil(2)FloatAlways down or up
x.round(-2)IntegerRound to hundreds
format("%.2f", x) or "%.2f" % xStringFixed two decimals for display, trailing zeros kept
x.truncate(2)FloatCut off the extra digits toward zero
BigDecimal("2.675").round(2)BigDecimalExact decimal arithmetic for money

Pitfalls

  • Float representation. 0.1 + 0.2 is 0.30000000000000004; rounding hides it for display, but sums of many Floats still drift. Store money as integer cents or BigDecimal.
  • Rounding a String. "3.14159".round(2) raises NoMethodError (undefined method round for an instance of String); convert with Float() or to_f first.
  • Wrong arguments. round("2") raises TypeError (no implicit conversion of String into Integer), and round(2, :even) without the half: keyword raises wrong number of arguments (given 2, expected 0..1).
  • BigDecimal is a gem. Since Ruby 3.4, bigdecimal is a bundled gem rather than a default gem: require "bigdecimal" works in a standard installation, but with Bundler it must be listed in the Gemfile, and Ruby 3.4 prints a warning when it is missing.
  • puts vs p. puts 5.0.round(2) prints 5.0, p prints the same with quotes for Strings; see puts vs print vs p.

Confirm it worked

Print the value with p to see whether it is a Float (3.14) or a String ("3.14"), and test a value ending in 5 (2.675, 2.5) to check that the rounding mode is the one you want.

FAQ

Why does 2.675.round(2) give 2.68 in Ruby but 2.67 in Python?

Ruby's Float#round rounds the decimal number closest to the float, while Python's round works on the exact binary value, which is slightly below 2.675. Print the results in both languages before relying on either for money; use BigDecimal or integer cents.

How do I always show two decimals, such as 5.00?

round returns a Float, and 5.0 prints as 5.0. Use format("%.2f", x), which returns the String "5.00".

How do I round down or up instead?

Float#floor(2) and Float#ceil(2) accept a number of digits too: 3.149.floor(2) is 3.14 and 3.141.ceil(2) is 3.15.

Sources