5 ms·
Because it's an abstraction on top of an abstraction on top of an abstraction. You need to leak parts of the lower layers to higher levels in order to get the s
by kstenerud 6y ago
Because it's an abstraction on top of an abstraction on top of an abstraction. You need to leak parts of the lower layers to higher levels in order to get the speed back (and allow zero-copy). There are probably some non-leaky optimizations that can be done as well, although that's been going on for decades.
Another biggie is floating point. Converting binary floating point to decimal floating point and vice versa is VERY VERY VERY SLOW, difficult to get right, and difficult to predict results. Unfortunately, ieee754 decimal float just isn't getting any adoption, so we're stuck doing these costly conversions every time we deal with text formats or big float implementations.
Actually, scanf and printf are just in general slow because of their general nature. They need to handle a TON of options and get really bloated and complicated as a result.
- 77pt77 6y ago> Another biggie is floating point. Converting binary floating point to decimal floating point and vice versa is VERY VERY VERY SLOW, difficult to get right Never forget the cluster bug in PHP because the developers decided they needed to reinvent the wheel[1]. [1] https://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ https://www.exploringbinary.com/php-hangs-on-numeric-value-2...
- ars 6y agoCan you explain what you mean? Because I read the bug report and it seems to be some intricacy about loading variables into a register solved by using volatile. Meaning it's a complicated implementation detail of the CPU, and does not seem to be because they reinvented the wheel. Plus is there some standardized library they should have been using?
- hyperman1 6y agoJava had a variant of that bug too: https://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ https://www.exploringbinary.com/java-hangs-when-converting-2... It sits in a loop flip-flopping between 2 representations, each time deciding the other one is better. This turned into a DOS, as some web servers used floating point when decoding time zones from the http request header. So if your server has e.g. 20 http acceptor threads, someone could send 20 requests with an insane time zone, each sending 1 thread in an infinite loop.
- deleted 6y ago[deleted]
- thethirdone 6y ago> Another biggie is floating point. Converting binary floating point to decimal floating point and vice versa is VERY VERY VERY SLOW, difficult to get right, and difficult to predict results. I haven't read deeply into IEEE 754-2008 for decimal floating points, but it seems like it should be pretty fast (relative to system calls) to convert binary to decimal because 10 has a factor of 2. > Unfortunately, ieee754 decimal float just isn't getting any adoption, so we're stuck doing these costly conversions every time we deal with text formats or big float implementations. Is there any reason big float implementations should use decimal rather than binary? It seems like it is very straightforward to make a binary big float, and do operations on it. In fact, IEEE 754-2008 specifies interchange formats for all binary floats of bit lengths >= 128 where length is a multiple of 32.
- saagarjha 6y ago> it seems like it should be pretty fast (relative to system calls) to convert binary to decimal because 10 has a factor of 2 I don’t see how this would matter?
- thethirdone 6y agoAny binary float is exactly representable in a decimal float with enough digits. This is not true in the other direction. for example 1/5th or 0.2 is 0.001100110011... in binary. So a simple solution for binary to decimal is to express it as a larger decimal float than you intend to show and then crop off digits if it doesn't fit in your destination format.
- kstenerud 6y ago> haven't read deeply into IEEE 754-2008 for decimal floating points, but it seems like it should be pretty fast (relative to system calls) to convert binary to decimal because 10 has a factor of 2. It could be fast, but legacy has doomed us all to a "canonical" conversion of sorts, where any other conversion algorithm will likely yield off-by-a-tiny-amount differences in the binary format (like 1.200000000031 instead of 1.2). There are in fact fairly simple conversions that can be done, but they yield results that are incompatible with printf. > Is there any reason big float implementations should use decimal rather than binary? At the end of the day, we work in decimal. So every binary result we calculate has to be converted to its decimal approximation (the meaning of which is subject to convention). Rounding is also an issue, because you want to keep your number of significant digits within reason to avoid false precision errors. Doing all of this in a different base that can't be 1:1 converted adds a whole slew of bug opportunities and corner cases.
- asveikau 6y agoI think you are over counting abstractions. printf copies to a buffer and eventually calls write(2). On Windows there is an additional layer: CRT implements unix-style integer file descriptors (io.h) before calling WriteFile.
- kstenerud 6y agoIt's usually printf() -> fwrite() -> write() -> syscall. You need the fwrite (or something equivalent) in there for buffering and concurrency, otherwise multithreaded printfs would stomp on each other.
- saagarjha 6y agoUsually you go through vfprintf, which is the “most generic” function, and that will grab the file’s lock.
- haberman 6y ago> Converting binary floating point to decimal floating point and vice versa is VERY VERY VERY SLOW The fastest dtoa() algorithms are on the order of 50ns or less: https://erthink.github.io/dtoa-benchmark/#results https://erthink.github.io/dtoa-benchmark/#results There are probably a lot of implementations lagging behind the state of the art though...
- dathinab 6y agoThe problem is if it's still behaving exactly the same for certain edge cases. I don't know about stdio, but in Java there are a bunch of float operations in the standardlibrary which can be easily implemented much faster and simpler, but then misbehave in that one edge cases most people don't care about.
- klodolph 6y ago> The problem is if it's still behaving exactly the same for certain edge cases. It is behaving correctly for all edge cases. That’s the benchmark you compare floating-point to decimal conversion—your algorithm is no good if it doesn’t handle all cases. The start of the art back in the 1990s the algorithm used in dtoa, written by David M. Gay and included in Netlib, taken from a paper by Steele (I think). Since then, people have chipped away at the problem, making it faster. A few new algorithms have appeared, including Grisu and Ryu. Something you’ll see in these algorithms is some “fast path” which uses ordinary double arithmetic, and then logic to detect when this gives the wrong answer and fall back to some slower path. The slower path may use arbitrary precision arithmetic or something else (Ryu avoids bignums!). These new algorithms generally hit the slow path very infrequently, which is why you sometimes see benchmarks with numbers picked to trigger the slow path. The algorithms have associated papers proving their correctness for all inputs. You are free to read them. https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/p... https://dl.acm.org/doi/10.1145/3192366.3192369 https://dl.acm.org/doi/10.1145/3192366.3192369