Live data from Hacker News

C Is Not Reasonable

osr.com

61–70 of 71 posts

Re: C Is Not Reasonable

#61
post #16

The way to understand it is that "+" when applied to ULONGs returns a ULONG. What the heck else it would return, in a language that doesn't have arbitrary precision arithmetic?

If it were consistent with FLT_EVAL_METHOD==2, then it would evaluate in the highest precision available.

There's a lot of smug criticism of this article, but there actually is a reasonable point that FLT_EVAL_METHOD is inconsistent with the way integers are handled in C.

Re: C Is Not Reasonable

#62

Earlier quoted context omitted.

Respectfully, this misses my point (which, granted, was poorly explained). The necessary evil here is using low-level languages. The unnecessary evil is using a language like C with arbitrary and highly variant conventions. Better alternatives exist for writing drivers (e.g. Rust). To be clear, historical baggage sometimes dictates that we must use C, but that doesn't change the fact that much of the C world is a foo…

Rust and its ilk may eventually eat this space, but it doesn't appear ready. For one, it's list of supported architectures is too small. For two, it's poorly optimized, when compared to C. Three, it's still too new - it has only been "stable" for a bit over a year. Four, the static verification tools are not yet there (you still need a way to verify the unsafe portions of code, which will not be trivial in a driver).…

  >  For two, it's poorly optimized, when compared to C
I'd be interested in hearing more about this.

Re: C Is Not Reasonable

#63
post #16

The way to understand it is that "+" when applied to ULONGs returns a ULONG. What the heck else it would return, in a language that doesn't have arbitrary precision arithmetic?

If it were consistent with FLT_EVAL_METHOD==2, then it would evaluate in the highest precision available. There's a lot of smug criticism of this article, but there actually is a reasonable point that FLT_EVAL_METHOD is inconsistent with the way integers are handled in C.

That's a good point.

Re: C Is Not Reasonable

#64

Earlier quoted context omitted.

This will lose precision, as any floating point operation is only accurate to 1 unit in the last place (ULP). Even simple addition.

This conversion will not lose precision! With a 64-bit mantissa, ULP(x) is ≤ 1 for x in [-2e64, 2e64]. If you have the time you can count up to 2^64 by repeatedly incrementing a float80(0.0) by 1. Addition, subtraction and multiplication on float80s are perfectly stable provided the results stays within [-2e64, 2e64].

There is no guarantee on stability of those ops. Intel and IEEE guarantees 1 ULP. Even if you use the 80 bit type. The error is not guaranteed to not be additive over multiple operations either. And for multiplication and division? Let's not even go there.

This will mess up all kinds of sharp comparisons on the result of casted operations.

Re: C Is Not Reasonable

#65
post #49
post #7

Arithmetic is surprisingly hard to get "right". You might try to generalise from this example that "multiplying two N bit numbers together should give a result 2N" wide, then discover that for simple examples you run out of machine bits. Then there's overflow/saturation handling, which is a mess everywhere: lots of systems have hardware support for saturation arithmetic, but you can't conveniently specify it in C. If…

> then discover that for simple examples you run out of machine bits Why? I don't think it would be common to run out of machine bits for correct programs (and not really run out, just go into bigints in some cases). But the compiler cannot calculate those bits based on machine types, instead it should track all possible values/ranges and multiply them too to decide whether the result could fit into the type or it ne…

Generally, for fixed point operation you need to explicitly handle two things: overflow and rounding. The former may not be an issue in some applications, but the latter will. It is easy to introduce a cumulative error by incorrect rounding for instance.

Re: C Is Not Reasonable

#66
post #32

Programming practically requires a willingness to continue learning. But his statements are deeply troubling: > I’m not annoyed by the way statements are formed, or even by the precedence order (which I readily admit to not knowing or understanding or even caring much about) > And don’t complain about how I parenthesize my arithmetic statements. I already mentioned precedence order. All those parens are the result of…

Whilst the delivery could be better, I agree with the sentiment that operator precedence is a waste of time. It's exactly the kind of mundane, error-prone work that machines should be doing for us, whether it's via a sophisticated structured editor, or a simple hack like Emacs's various paredit-like modes. > Sure, you can pepper all your code in parentheses, but sooner or later you're going to come across code that d…

> Lisp, Forth and friends do perfectly well without having to consult precedence tables

It helps that they have "alien" syntaxes (prefix or postfix but not infix). Smalltalk is also a language which did away with precedence almost entirely: it has a strict right-to-left evaluation model, and only three precedence levels[0]: unary messages (aSubject aMessage), binary messages (aValue anOtherValue) and keyword messages (aSubject aMessage: aValue) but because it has "infix operators" the effect is much weirder.

[0] or possibly a fourth, the cascading `;` operator is not a message, and can become really, really weird when used with different message types e.g.

    7 + 4 squared; factorial; yourself.
binds like this:

    7 (+ (4 squared)); factorial; yourself.
so it computes 4 squared, adds it to 7, then computes the factorial of 7 and finally returns 7.

Re: C Is Not Reasonable

#67

Earlier quoted context omitted.

> or allow the programmer to specify which one should be used with an annotation. That's exactly: > give all of those functions different names.

Effectively; although "name" usually implies an opaque symbol, e.g. the language would see no difference between, say, "addAsInts" vs. "addAsFloats", compared to "addAsInts" vs. "divide". Classes, namespaces, modules, etc. allow names to have a more fine-grained structure, e.g. "int.add" and "int.divide" come from the same module, whilst "int.add" and "float.add" are alternative implementations of the same signature.

> whilst "int.add" and "float.add" are alternative implementations of the same signature.

Maybe in a functional programming language like Haskell. But not in C++.

Re: C Is Not Reasonable

#68

Earlier quoted context omitted.

Respectfully, this misses my point (which, granted, was poorly explained). The necessary evil here is using low-level languages. The unnecessary evil is using a language like C with arbitrary and highly variant conventions. Better alternatives exist for writing drivers (e.g. Rust). To be clear, historical baggage sometimes dictates that we must use C, but that doesn't change the fact that much of the C world is a foo…

Rust and its ilk may eventually eat this space, but it doesn't appear ready. For one, it's list of supported architectures is too small. For two, it's poorly optimized, when compared to C. Three, it's still too new - it has only been "stable" for a bit over a year. Four, the static verification tools are not yet there (you still need a way to verify the unsafe portions of code, which will not be trivial in a driver).…

Okay, point taken, but I'd like to back-pedal a bit if you don't mind. I agree that Rust is very immature, but again I think I misspoke.

The basic point I'm trying to make is that C is (a) fraught with historical baggage that makes it difficult to use safely, in practice and that (b) this comment thread proves this point.

All points made beyond this are secondary and tangential. Again, I have to agree with you about the maturity of Rust, but I must insist that using C is fraught with absolute insanity. Sometimes it's the only thing available, but it's still insane.

Re: C Is Not Reasonable

#69

Earlier quoted context omitted.

Effectively; although "name" usually implies an opaque symbol, e.g. the language would see no difference between, say, "addAsInts" vs. "addAsFloats", compared to "addAsInts" vs. "divide". Classes, namespaces, modules, etc. allow names to have a more fine-grained structure, e.g. "int.add" and "int.divide" come from the same module, whilst "int.add" and "float.add" are alternative implementations of the same signature.

> whilst "int.add" and "float.add" are alternative implementations of the same signature. Maybe in a functional programming language like Haskell. But not in C++.

The syntax was just an example ;)

What I described is actually closer to ML.

Re: C Is Not Reasonable

#70
post #49

Earlier quoted context omitted.

> then discover that for simple examples you run out of machine bits Why? I don't think it would be common to run out of machine bits for correct programs (and not really run out, just go into bigints in some cases). But the compiler cannot calculate those bits based on machine types, instead it should track all possible values/ranges and multiply them too to decide whether the result could fit into the type or it ne…

Generally, for fixed point operation you need to explicitly handle two things: overflow and rounding. The former may not be an issue in some applications, but the latter will. It is easy to introduce a cumulative error by incorrect rounding for instance.

I suppose rounding is solvable too. Depending of how value is used at the end it would be possible to deduce how much precision is needed to guarantee no cumulative error.
Post reply on HN