3 ms·
// Does the same as `Number.prototype.toFixed` but without casting // the return value to a string. function toFixed(num, precision) { const pow
by jdmichal 4y ago
// Does the same as `Number.prototype.toFixed` but without casting
// the return value to a string.
function toFixed(num, precision) {
const pow = 10 ** precision;
return Math.round(num * pow) / pow;
}
I know doubles are big, but doesn't this combination of multiply-and-divide introduce the possibility of precision issues that I'm assuming is not applicable to `toFixed`?
Unless I'm wrong, I would be very hesitant to use this version of the method when I don't control the input.
- aeyes 4y agoThis is processing numbers which appear in SVG files which are basically coordinates, they aren't that big.
- chrismorgan 4y agoThis need not be true: you can put objects and viewboxes wherever you like in SVG. <svg viewBox="1234567890 1234567890 100 100"> is perfectly valid. Many years ago (Adobe SVG Viewer days) my Dad generated SVG files from geo/map data and at first used the original coordinates or something, but float error made it untenable—some viewers would end up quantising some things (e.g. the shape, the viewbox, individual nodes, even once you applied a transform or SMIL animation to them, the hover hitboxes—I don’t remember the particular details, but it was a few things) so they’d end up off by as much as hundreds of pixels in the most extreme projections. Therefore he ended up rezeroing to work around this, transforming into a more friendly space before producing the file. In the context of SVGO: really, the whole decimal places thing is stupidly bad, because decimal places can be of wildly differing importance in different contexts, and it wouldn’t be that hard to figure most of them out. In some situations a third decimal place will be more valuable than another number’s hundreds place. And SVGO’s approach is particularly bad because it treats each number individually, not attempting to compensate for the error it introduces, and so the presence of fine detail can easily completely destroy things due to untreated cumulative error.
- ygra 4y agoI wouldn't expect SVGs that require double precision to render anywhere properly. Most renderers these days use 32-bit floats simply because it's easier to get things to render on the GPU that way, so at very large or very small scales things tend to break in fun ways.
- jansan 4y agoThere certainly are issues with precision: toFixed(1000.005, 2); // returns 1000.01 toFixed(1.005, 2) // returns 1 Rounding to a fixed number of fraction decimals is extremely tricky, much trickier than it appears on first view. This is beaten to death at Stackoverflow, but I can tell you that almost all (or all?) of the solutions provided don't work for all cases: https://stackoverflow.com/questions/11832914/how-to-round-to-at-most-2-decimal-places-if-necessary/11832950#11832950 https://stackoverflow.com/questions/11832914/how-to-round-to...
- maccard 4y agoThis is an argument for having these fundamentals implemented in the language's standard library IMO.
- Valter42 4y agoThis toFixed is if the precision is below 16, JS just doesn't work with more, you literally can't have more than 16 digits after the decimal, JS will round it (very poorly btw) BTW if one needs to round to more than 16 you can use toLocaleString and pass minimum and maximum fraction digits which has a limit of 20. Ain't much but you could not expect more from JS :D