Skip to content
Joey Wang
Menu

Search

Full Stack Development

Round Is Not Always What You Expect

Rounding the same float, 2.675, to two decimal places gives different answers in C#, PHP, Go, Python, JavaScript, and Ruby, for concrete reasons.

· 2 min read

engineering #ruby#javascript#debugging

Audio summary

Rounding looks like a solved problem until you compare languages. Take the same float, 2.675, round it to two decimal places, and you get three different answers depending on which language you’re using and which rounding rule it defaults to.

CSharp

In C#, the Math.Round function provides a default rounding behavior, but you can also specify how to handle midpoints with the MidpointRounding enumeration.

using System;

class Program
{
    static void Main()
    {
        double number = 2.675;
        Console.WriteLine(Math.Round(number, 2)); // Default rounding, results in 2.7
        Console.WriteLine(Math.Round(number, 2, MidpointRounding.AwayFromZero)); // Rounds to 2.68
    }
}

When you run this C# program, you’ll notice that the default rounding gives you 2.7, but by specifying MidpointRounding.AwayFromZero, the result becomes 2.68.

PHP

PHP’s round function uses the “round half up” method by default, which means it rounds .5 up to the nearest higher value.

<?php
print "round(2.675, 2) = " . round(2.675, 2);
?>

If you run this PHP script, the output will be:

round(2.675, 2) = 2.68

Go

Go’s math.Round function rounds a floating-point number to the nearest integer, but we can adapt it for specific decimal places.

package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Printf("round(2.675, 2): %.3f", math.Round(2.675*100)/100)
}

Running the Go program will give you the output:

round(2.675, 2): 2.68

Python

Python’s round function also uses “round half to even,” which means it rounds to the nearest even number when encountering a .5.

print("round(2.675, 2) = ", round(2.675, 2))

Interestingly, the Python script outputs:

round(2.675, 2) =  2.67

This is because Python rounds 2.675 to 2.67 instead of 2.68, following the “round half to even” rule.

JavaScript

JavaScript’s .toFixed method formats a number using fixed-point notation, and when converted back to a number, it rounds according to standard rounding rules.

console.log("Number((2.675).toFixed(2))", Number((2.675).toFixed(2)));

The output in the JavaScript console will be:

Number((2.675).toFixed(2)) 2.67

Ruby

Ruby’s round method rounds to the nearest value, and when it encounters a .5, it rounds to the nearest even number.

puts "2.675.round(2) = #{2.675.round(2)}"

When you run this Ruby code, the result is:

2.675.round(2) = 2.68

The takeaway

C#, PHP, Go, and Ruby all land on 2.68 here. Python’s round and JavaScript’s toFixed both land on 2.67, and neither is “wrong”: 2.675 cannot be represented exactly in binary floating point, so which side of the boundary you end up on depends on the language’s rounding algorithm as much as on the number itself. The rule that matters isn’t “which language rounds correctly,” it’s “what rounding mode does this language default to, and can I override it.” Check the docs before you assume, especially in code that touches money.