Skip to content

Commit

Permalink
Fix #14 - format negative zero as zero.
Browse files Browse the repository at this point in the history
Negative zero is a construct of IEEE 754 floating point, not a mathematical
concept that (most) humans should care about. And since you may see tick values
that are very small negative numbers due to limited precision, such as -8e-17,
it’s helpful to format these as zero (“0.00”), not negative zero (“-0.00”).
  • Loading branch information
mbostock committed Nov 6, 2015
1 parent 34d08b8 commit 74f1cd9
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 4 deletions.
15 changes: 15 additions & 0 deletions src/locale.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ export default function(locale) {
// Perform the initial formatting.
value = formatType(value, precision);

// If the original value was negative, it may be rounded to zero during
// formatting; treat this as (positive) zero.
if (valueNegative) {
var i = -1, n = value.length, c;
valueNegative = false;
while (++i < n) {
if (c = value.charCodeAt(i), (48 < c && c < 58)
|| (type === "x" && 96 < c && c < 103)
|| (type === "X" && 64 < c && c < 71)) {
valueNegative = true;
break;
}
}
}

// Compute the prefix and suffix.
valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
Expand Down
5 changes: 3 additions & 2 deletions test/format-type-d-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ tape("format(\"-,d\") explicitly only use a sign for negative numbers", function
test.end();
});

tape("format(\"d\") can format negative zero", function(test) {
test.equal(format.format("1d")(-0), "-0");
tape("format(\"d\") can format negative zero as zero", function(test) {
test.equal(format.format("1d")(-0), "0");
test.equal(format.format("1d")(-1e-12), "0");
test.end();
});
6 changes: 6 additions & 0 deletions test/format-type-e-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ tape("format(\"e\") can output exponent notation", function(test) {
test.end();
});

tape("format(\"e\") can format negative zero as zero", function(test) {
test.equal(format.format("1e")(-0), "0.000000e+0");
test.equal(format.format("1e")(-1e-12), "-1.000000e-12");
test.end();
});

tape("format(\",e\") does not group Infinity", function(test) {
test.equal(format.format(",e")(Infinity), "Infinity");
test.end();
Expand Down
5 changes: 3 additions & 2 deletions test/format-type-f-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ tape("format(\"f\") can display integers in fixed-point notation", function(test
test.end();
});

tape("format(\"f\") can format negative zero", function(test) {
test.equal(format.format("1f")(-0), "-0.000000");
tape("format(\"f\") can format negative zero as zero", function(test) {
test.equal(format.format("1f")(-0), "0.000000");
test.equal(format.format("1f")(-1e-12), "0.000000");
test.end();
});

Expand Down
10 changes: 10 additions & 0 deletions test/format-type-x-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ tape("format(\"x\") rounds non-integers", function(test) {
test.end();
});

tape("format(\"x\") does not consider -0xeee to be positive", function(test) {
test.equal(format.format("x")(-0xeee), "-eee");
test.end();
});

tape("format(\"X\") returns the expected hexadecimal (uppercase) string", function(test) {
test.equal(format.format("X")(0xdeadbeef), "DEADBEEF");
test.end();
Expand All @@ -60,6 +65,11 @@ tape("format(\"#X\") returns the expected hexadecimal (uppercase) string with pr
test.end();
});

tape("format(\"X\") does not consider -0xeee to be positive", function(test) {
test.equal(format.format("X")(-0xeee), "-EEE");
test.end();
});

tape("format(\"#[width]x\") considers the prefix", function(test) {
test.equal(format.format("20x")(0xdeadbeef), " deadbeef");
test.equal(format.format("#20x")(0xdeadbeef), " 0xdeadbeef");
Expand Down

0 comments on commit 74f1cd9

Please sign in to comment.