color icon indicating copy to clipboard operation
color copied to clipboard

Rounding errors with Color.hsl().string()

Open s2tephen opened this issue 7 years ago • 15 comments

Certain colors (I've only seen this in HSL so far) don't round correctly when calling string().

For example:

var Color = require('color');

var pink = Color('#FF08C2');
console.log(pink.hsl().string()); // 'hsl(314.79999999999995, 100%, 51.6%)'

s2tephen avatar Sep 26 '17 00:09 s2tephen

Observed when using RGBA color('#000').fade(0.9).string(); returns "rgba(0, 0, 0, 0.09999999999999998)"

jacksenior avatar Feb 20 '18 08:02 jacksenior

Which version of color?

Qix- avatar Feb 24 '18 04:02 Qix-

@Qix- This issue can be observed in node 9.8.0 and with color 3.0.0. This is due to floating point error. There are different ways of dealing with this, possibly using toPrecision.

henopied avatar Mar 11 '18 03:03 henopied

@henopied Aware it's a rounding problem. I thought it was fixed in color-string, though. Let me investigate.

Qix- avatar Mar 12 '18 20:03 Qix-

Any news on this issue?

astrotim avatar Oct 19 '18 06:10 astrotim

Possibly related. Alpha value don't seem to get rounded

rgba(47, 64, 85, 0.0784313725490196) hsla(213, 29%, 26%, 0.0784313725490196)

I agree that my input values might be a bit weird but the figma API is returning them unrounded as well.

iamgoodbytes avatar Mar 13 '19 13:03 iamgoodbytes

This feature would be really great. I don't know why fading a color by 0.8 returns a color with a valpha of 0.19999999999999996, but when you've got a lot of colors that end up like this it gets pretty messy to look at.

fade(0.8) >>> valpha = 0.19999999999999996 fade(0.7) >>> valpha = 0.30000000000000004

Everything else I've tried has returned a round number as expected.

Nantris avatar Nov 10 '19 00:11 Nantris

@Slapbox please read this article before complaining about your particular case of rounding. That's not what the OP is facing, per se.

Qix- avatar Nov 10 '19 00:11 Qix-

@Qix it's a rounding error nonetheless. Would you prefer I open a new issue then?

Nantris avatar Nov 11 '19 18:11 Nantris

@Slapbox No, because the rounding error you're reporting is only fixable by the IEEE. Feel free to open a bug report regarding the IEEE-754 standard.

Qix- avatar Nov 12 '19 04:11 Qix-

@Qix- I understand calculations are done with floating points, but surely you're not telling me that we can't round 0.19999999999999996 when we're done with calculations and getting a string value with .rgb().string().

Nantris avatar Nov 12 '19 21:11 Nantris

@slapbox I'm not sure why you're pushing so hard on this. Yes it can be rounded, I just want to make sure you understand where your errors are coming from as opposed to OP's.

Qix- avatar Nov 13 '19 01:11 Qix-

Have their been any decisions made on this issue? Still occurring in 3.1.3

gordonnl avatar Mar 05 '21 12:03 gordonnl

It's not just alpha, hue is not rounded in certain conditions. For example, converting tomato to hsl even with round() or round(1) or no round results in unrounded hue:

Color('tomato').hsl().round().string()  === "hsl(9.100000000000023, 100%, 63.9%)"
Color('tomato').hsl().round(1).string() === "hsl(9.100000000000023, 100%, 63.9%)"
Color('tomato').hsl().round(5).string() === "hsl(9.100000000000023, 100%, 63.9%)"
Color('tomato').hsl().string()          === "hsl(9.100000000000023, 100%, 63.9%)"

This happens in 3.1.3.

bbugh avatar Jun 29 '21 02:06 bbugh

The bug is that the library is taking a floating point number, using toFixed() to convert it to a rounded number in string form, then immediately converting back into a floating point number again.

		return new Color(this.color.map(roundToPlace(places)).concat(this.valpha), this.model);

and

let self = this.model in colorString.to ? this : this.rgb();
self = self.round(typeof places === 'number' ? places : 1);
const args = self.valpha === 1 ? self.color : self.color.concat(this.valpha);
return colorString.to[self.model](args);

The rounding needs to happen at the last minute when the result is passed back to the caller of .string() or .hex() etc.

(Nothing to do with the IEEE.)

stevage avatar Mar 31 '22 04:03 stevage