Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #174243 > unrolled thread
| Started by | candycane@f172.n1.z21.fsxnet (candycane) |
|---|---|
| First post | 2023-09-06 19:53 +1300 |
| Last post | 2023-09-09 10:23 -0700 |
| Articles | 20 on this page of 129 — 12 participants |
Back to article view | Back to comp.lang.c
Re: bart again (UCX64) candycane@f172.n1.z21.fsxnet (candycane) - 2023-09-06 19:53 +1300
Re: bart again (UCX64) Richard Damon <Richard@Damon-Family.org> - 2023-09-07 12:00 -0700
Re: bart again (UCX64) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-09-07 16:33 -0700
Re: bart again (UCX64) Richard Damon <Richard@Damon-Family.org> - 2023-09-07 20:55 -0700
Re: bart again (UCX64) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-09-07 22:16 -0700
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-08 07:09 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-08 10:10 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-08 01:30 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-08 11:26 +0200
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-08 10:44 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-08 13:26 +0200
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-09 01:57 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-09 18:36 +0200
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-09 18:19 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-10 13:28 +0200
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-10 13:20 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-10 15:19 +0200
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-10 16:07 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-10 18:33 +0200
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-10 15:44 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-10 18:36 +0200
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-09 01:48 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-09 19:04 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-08 02:47 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-08 16:03 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-08 16:06 -0700
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-09 01:52 +0100
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-08 18:16 -0700
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-09 21:31 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-10 12:03 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-10 21:36 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-11 08:51 +0200
Re: bart again (UCX64) "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2023-09-10 23:59 -0700
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-11 01:01 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-11 11:17 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-11 03:16 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-11 14:58 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-11 06:35 -0700
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-11 14:13 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-11 16:24 +0200
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-11 14:55 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-11 16:42 +0200
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-11 14:29 +0000
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-11 11:25 +0100
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-11 03:59 -0700
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-11 13:57 +0000
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-11 09:52 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-11 16:07 +0200
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-11 16:26 +0100
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-11 16:47 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-11 19:14 +0200
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-11 22:30 +0100
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-11 23:07 +0100
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-11 23:31 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-12 09:18 +0200
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-12 03:01 +0100
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-11 10:08 -0700
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-11 23:18 +0100
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-11 23:37 +0100
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-11 15:46 -0700
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-11 23:40 +0000
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-12 01:50 +0100
Re: bart again (UCX64) Richard Damon <Richard@Damon-Family.org> - 2023-09-11 17:59 -0700
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-12 01:03 +0000
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-12 02:39 +0100
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-12 11:28 +0100
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-12 14:49 +0100
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-12 15:18 +0100
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-12 03:58 +0100
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-12 02:25 -0700
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-12 16:17 +0100
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-12 17:28 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-12 21:07 +0200
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-13 03:01 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-13 09:38 +0200
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-13 10:00 +0200
Re: bart again (UCX64) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-19 05:22 -0700
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-19 14:29 +0100
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-13 13:35 +0100
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-13 20:48 +0100
Re: bart again (UCX64) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-19 05:53 -0700
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-12 09:33 -0700
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-12 16:48 +0000
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-12 10:57 -0700
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-12 18:07 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-12 21:23 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-13 02:07 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-13 12:43 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-13 04:04 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-13 14:07 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-13 01:47 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-13 13:02 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-13 04:45 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-13 14:36 +0200
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-13 13:43 +0000
Re: bart again (UCX64) James Kuyper <jameskuyper@alumni.caltech.edu> - 2023-09-13 11:10 -0400
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-13 17:12 +0000
[meta] spam in thread Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-13 11:22 -0700
Re: [meta] spam in thread Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-13 18:40 +0000
Re: [meta] spam in thread Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-13 11:48 -0700
Re: [meta] spam in thread David Brown <david.brown@hesbynett.no> - 2023-09-13 21:01 +0200
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-13 19:58 +0100
Re: bart again (UCX64) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-18 12:36 -0700
Re: bart again (UCX64) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-09-18 13:40 -0700
Re: bart again (UCX64) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-20 19:43 -0700
Re: bart again (UCX64) "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2023-09-20 20:14 -0700
Re: bart again (UCX64) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-09-20 22:10 -0700
Re: bart again (UCX64) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-10-01 11:03 -0700
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-13 07:39 -0700
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-13 15:18 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-13 18:39 +0200
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-13 15:44 +0100
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-13 08:42 -0700
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-13 22:35 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-13 18:49 +0200
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-11 15:40 -0700
Re: bart again (UCX64) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-12 03:36 +0100
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-12 12:58 +0200
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-12 12:49 +0200
Re: bart again (UCX64) Bart <bc@freeuk.com> - 2023-09-12 12:52 +0100
Re: bart again (UCX64) Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-09-12 05:22 -0700
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-12 15:05 +0200
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-09 02:17 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-10 14:44 +0200
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-08 14:36 +0000
Re: bart again (UCX64) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-09 01:50 +0000
Re: bart again (UCX64) scott@slp53.sl.home (Scott Lurndal) - 2023-09-09 15:40 +0000
Re: bart again (UCX64) David Brown <david.brown@hesbynett.no> - 2023-09-08 09:57 +0200
Re: bart again (UCX64) Richard Damon <Richard@Damon-Family.org> - 2023-09-09 10:23 -0700
Page 2 of 7 — ← Prev page 1 [2] 3 4 5 6 7 Next page →
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-09-10 18:36 +0200 |
| Message-ID | <udkrau$kuso$2@dont-email.me> |
| In reply to | #174844 |
On 10/09/2023 17:44, Kaz Kylheku wrote: > On 2023-09-10, David Brown <david.brown@hesbynett.no> wrote: >> I don't see "unreachable()" as saying "insert UB here". > > But you must think of it that way, if it is specified that way > in its documentation. E.g. the GCC one: > > Built-in Function: void __builtin_unreachable (void) > > If control flow reaches the point of the __builtin_unreachable, the > program is undefined. It is useful in situations where the compiler > cannot deduce the unreachability of the code. > I know how it works (I have read most of the gcc manual, and I read that description before first using __builtin_unreachable). But if you read that sentence, it is a conditional - "/if/ control flow reaches the point...". Control flow will /not/ reach the point in my code that has "unreachable()", thus no undefined behaviour is introduced.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-09 01:48 +0000 |
| Message-ID | <20230908184633.897@kylheku.com> |
| In reply to | #174517 |
On 2023-09-08, Bart <bc@freeuk.com> wrote: > It's funny that some people don't want the bother of writing 'return 0;' > in a path they know will never be reached, while others are prepared to > write 'unreachable();', which is both longer and uses shifted characters. What is worse, the original program with a missing "return 0;" might well be correct. If the caller doesn't extract the return value, everything is copacetic. Whereas unreachable() is a gizmo whose only meaning is that it invokes undefined behavior if executed! It's like you have a pepper shaker on your programing table labeled "UB", and you sprinkle that on your program. -- TXR Programming Language: http://nongnu.org/txr Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal Mastodon: @Kazinator@mstdn.ca NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-09-09 19:04 +0200 |
| Message-ID | <udi8i5$52sl$4@dont-email.me> |
| In reply to | #174664 |
On 09/09/2023 03:48, Kaz Kylheku wrote: > On 2023-09-08, Bart <bc@freeuk.com> wrote: >> It's funny that some people don't want the bother of writing 'return 0;' >> in a path they know will never be reached, while others are prepared to >> write 'unreachable();', which is both longer and uses shifted characters. > > What is worse, the original program with a missing "return 0;" might > well be correct. If the caller doesn't extract the return value, > everything is copacetic. > > Whereas unreachable() is a gizmo whose only meaning is that it invokes > undefined behavior if executed! > > It's like you have a pepper shaker on your programing table labeled > "UB", and you sprinkle that on your program. > That's the joy of undefined behaviour :-) Several years back, I had to deal with finding bugs in a code base where the programmer had regularly muddled up function parameters and return types. Most people like to have global functions declared in a header, and include that header in the C file that defines the function and any C files that use the function - then they get everything nice and consistent. The code base that this programmer had started with, before he screwed around with it, was organised like that. (I know - I wrote it, and my gcc setup will complain loudly if there are any missing or mismatched declarations.) But this guy frequently didn't bother including headers, or declaring his global functions in headers. Sometimes he had an extern declaration in the C file, sometimes he relied on ancient implicit function declaration. And he got it wrong - a lot. Functions would be defined with one set of parameters, and called from different C files with a different number or different type of parameters. Return types were equally random. But you can't just replace a missing "return x;" with "return 0;", even though the behaviour is defined. Sometimes the code without the return statement works by sheer luck, which the "return 0;" is a guaranteed and consistent failure. It had one feature I've never seen before, tying in with another thread here - it called main() recursively. From within an interrupt handler.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-09-08 02:47 -0700 |
| Message-ID | <543b9acc-de99-425c-bb1d-485e9f98889dn@googlegroups.com> |
| In reply to | #174513 |
On Friday, 8 September 2023 at 10:27:12 UTC+1, David Brown wrote: > On 08/09/2023 10:30, Malcolm McLean wrote: > > On Friday, 8 September 2023 at 09:10:20 UTC+1, David Brown wrote: > >> > >> Note that since trying to execute "unreachable()" (as the C23 function > >> is called) is undefined behaviour, compilers can freely add debugging > >> and fault-finding options to give a run-time diagnostic if the code is > >> actually reached. But if the standard had defined the behaviour of > >> "unreachable()" to be somewhat like "abort()", compilers would not be > >> free to use it for efficient optimisation, or to aid static analysis. > >> > > The difference is that the programmer might want to deliberately call > > abort() as part of the expected runtime behaviour of the program. Whilst > > unreachable() can only be called if he has made a programming error. > > However he might want to fall back to defined behaviour in the case of > > such an error. > If a programmer wants such behaviour, then he or she should know how to > write it. > > However compilers can run unreachable code tests which would otherwise > > be too expensive if they encounter an unreachable() statement. What > > they can't do is use the unreachable() statement as a proof that the > > code is in fact unreachable. > Compilers can, and do, do exactly that. C is very much a "trust the > programmer" language, not a hand-holding language. If I write > "unreachable();", I expect my compiler to believe me and trust that the > code cannot ever be reached (or that I don't care what happens if it > /is/ reached). I don't want it to add extra code to check if the code > is reached, or to call abort() if it is reached. What I want is for the > compiler to use that extra information to make other code more > efficient, and to allow more compile-time warnings and static error > checking. > > That's the deal with C - the compiler believes the programmer, and the > programmer is careful not to lie to the compiler. If you don't like > that, pick a different programming language. > > So if you are not sure the code point is unreachable, don't "call" > unreachable(). It's very simple. > This is a basic misunderstanding you have shown before. In your world, you should never wear a seatbelt, because if you are at risk of crashing into the car in front, you shouldn't be driving. Of course that's nonsense. Experienced driver will occasionally have moment of inattention. Very rarely, this will produce an accident, and then the seatbelt is a life saver. Of course most seatbelts are never used for their intended purpose. But it's still worth having. Similarly, if you know that code cannot be reached, then unreachable() can have undefined behaviour. But even experienced programmer make mistakes. Less so maybe in the sort of programming you do. In the sort of programming other people do, you often do have termination conditions which depend on various mathematically proven properties like convergence being correct. But of course threre could be a subtle programming error which means that the mathematical property isn't always met. So a defined behaviour fallback is potentially useful. "This can't happen, but if it does, give me this diagnostic".
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-09-08 16:03 +0200 |
| Message-ID | <udf9jn$3fta8$1@dont-email.me> |
| In reply to | #174518 |
On 08/09/2023 11:47, Malcolm McLean wrote: > On Friday, 8 September 2023 at 10:27:12 UTC+1, David Brown wrote: >> On 08/09/2023 10:30, Malcolm McLean wrote: >>> On Friday, 8 September 2023 at 09:10:20 UTC+1, David Brown wrote: >>>> >>>> Note that since trying to execute "unreachable()" (as the C23 function >>>> is called) is undefined behaviour, compilers can freely add debugging >>>> and fault-finding options to give a run-time diagnostic if the code is >>>> actually reached. But if the standard had defined the behaviour of >>>> "unreachable()" to be somewhat like "abort()", compilers would not be >>>> free to use it for efficient optimisation, or to aid static analysis. >>>> >>> The difference is that the programmer might want to deliberately call >>> abort() as part of the expected runtime behaviour of the program. Whilst >>> unreachable() can only be called if he has made a programming error. >>> However he might want to fall back to defined behaviour in the case of >>> such an error. >> If a programmer wants such behaviour, then he or she should know how to >> write it. >>> However compilers can run unreachable code tests which would otherwise >>> be too expensive if they encounter an unreachable() statement. What >>> they can't do is use the unreachable() statement as a proof that the >>> code is in fact unreachable. >> Compilers can, and do, do exactly that. C is very much a "trust the >> programmer" language, not a hand-holding language. If I write >> "unreachable();", I expect my compiler to believe me and trust that the >> code cannot ever be reached (or that I don't care what happens if it >> /is/ reached). I don't want it to add extra code to check if the code >> is reached, or to call abort() if it is reached. What I want is for the >> compiler to use that extra information to make other code more >> efficient, and to allow more compile-time warnings and static error >> checking. >> >> That's the deal with C - the compiler believes the programmer, and the >> programmer is careful not to lie to the compiler. If you don't like >> that, pick a different programming language. >> >> So if you are not sure the code point is unreachable, don't "call" >> unreachable(). It's very simple. >> > This is a basic misunderstanding you have shown before. No, I am not misunderstanding anything - but I think /you/ are greatly misunderstanding /me/. > > In your world, you should never wear a seatbelt, because if you are at > risk of crashing into the car in front, you shouldn't be driving. Not at all - that is not even remotely equivalent. I am surprised that someone as experience in programming as yourself does not see it immediately. The risks when driving are unknowns - other people on the road, icy patches, kids jumping out in front of the car, etc. Some things you have partial control over, such as how well you have learned to drive, others you don't - such as an unexpected sneeze. These are all inputs - and your code should always check and sanitize input data from unknown sources. Compile-time information is about the car and/or driver, not the trip. You check the seat is in the right position once, before starting, not every time you want to press a pedal. You trust that the experts do their job - you don't open up the wheel mountings to see if the brakes are in order, but trust the mechanic at the workshop. When you turn the steering wheel, the car's wheels turn - because the car "trusts" that the driver knows what he or she is doing. And more relevantly, when writing software, you check the code at many stages - you check it when writing it, you test it at run-time, you have other people check it in code reviews, you have your static error checking software check what it can. You don't whip together a bunch of code and deploy it on the basis of "it compiles, so it must be right - any serious issue would have given an error on compilation, not just a warning." /That/ would be more akin to driving without a seat belt. So - back to reality and programming. I write "unreachable()" for parts of the code that I know can never be reached, because that is useful information to readers and the compiler. I expect the compiler to trust me, and to make use of that information to optimise the code. That's the compiler's job - I write in clear, high-level C code, and it turns that into efficient object code. If I see someone has written code such as : abort(); // Can never reach this I know that something in the development process is broken or untrustworthy. Perhaps the programmer can't trust the compiler - there are occasions when people have no choice but to use poor quality tools, and even the best tools are not bug-free. Perhaps the programmer is inexperienced, and thinks this is a good idea. Perhaps the warnings used in the compiler complain if there is nothing there (such as if you use Bart's compiler in the examples discussed). Perhaps the project manager is inexperienced, and thinks this is a case of being "doubly safe". Certainly something is wrong. > Of course that's nonsense. Yes, I agree - your analogy was utter nonsense. > > Similarly, if you know that code cannot be reached, then unreachable() > can have undefined behaviour. No. We are talking here about run-time undefined behaviour. Since the code line will never be reached when running the program, there cannot be undefined behaviour from it (or defined behaviour, for that matter - there is /no/ behaviour as it does not run). > But even experienced programmer make > mistakes. Less so maybe in the sort of programming you do. In > the sort of programming other people do, you often do have termination > conditions which depend on various mathematically proven properties > like convergence being correct. But of course threre could be a subtle > programming error which means that the mathematical property isn't > always met. If there is a possibility of the code reaching that point, "unreachable()" would not be appropriate. It's a bit like noting that if you don't want to write some output to the terminal, writing "printf" is not appropriate. What is so difficult about writing what you mean when programming? Sure, programmers make mistakes. That's why you have code reviews, and testing. That's why you use a debugger, and sanitizers, and other tools. That's why it is important to write code that you mean, and not nonsense that you don't mean. And you don't write code that is untestable such as lines that cannot be reached, or code that makes no sense to a reviewer claiming to do something in impossible situations. > > So a defined behaviour fallback is potentially useful. "This can't happen, > but if it does, give me this diagnostic". Where did you learn about logic? From watching Monty Python? Things that can't happen, can't happen. If the thing /might/ happen, then it /can/ happen. Do you think I write my code by guesswork? Do you think I say to myself, "I guess this is unlikely, and I don't want to consider it - we'll pretend it it's impossible and tell the compiler its unreachable. I'm sure no one will notice" ?
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-09-08 16:06 -0700 |
| Message-ID | <7cf7b6bd-39d9-4e22-baee-e128cfb2f214n@googlegroups.com> |
| In reply to | #174578 |
On Friday, 8 September 2023 at 15:03:51 UTC+1, David Brown wrote:
> On 08/09/2023 11:47, Malcolm McLean wrote:
>
> > So a defined behaviour fallback is potentially useful. "This can't happen,
> > but if it does, give me this diagnostic".
> Where did you learn about logic? From watching Monty Python?
>
> Things that can't happen, can't happen. If the thing /might/ happen,
> then it /can/ happen.
>
> Do you think I write my code by guesswork? Do you think I say to
> myself, "I guess this is unlikely, and I don't want to consider it -
> we'll pretend it it's impossible and tell the compiler its unreachable.
> I'm sure no one will notice" ?
>
OK so
int sign(double x)
{
if (x < 0) return -1;
if (x == 0) retun 0;
if (x > 0) return 1;
/* unreachable */
}
Yes?
No. In David Brown world, no-one would ever make that mistake. In reality,
it's the sort of thing that is quite likely to slip through. In fact sign() needs
to return a double to handle the corner case properly.
It's NaN of course. The sign of NaN is NaN.
Or you could say that NaN isn't in the domain of the function and either catch
it, or just ignore it and accept any garbage - the real bug will be upstream.
Or you could say that the code is unreachable because we always filter
out NaN. But how would you prove that?
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2023-09-09 01:52 +0100 |
| Message-ID | <874jk4mam8.fsf@bsb.me.uk> |
| In reply to | #174644 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
> int sign(double x)
> {
> if (x < 0) return -1;
> if (x == 0) retun 0;
> if (x > 0) return 1;
> /* unreachable */
> }
Just for information...
> In fact sign() needs to return a double to handle the corner case properly.
>
> It's NaN of course. The sign of NaN is NaN.
In IEEE floating point (almost universal these days) NaNs (and
infinities) are signed, and the sign often carries useful information.
You can't just state that "the sign of NaN is NaN" as if it's a plain
fact. One might want, for example, something more like:
return x == 0 ? 0 : 1 - 2*signbit(x);
The information alluded to above being that some readers may not know
that C has a signbit macro.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-09-08 18:16 -0700 |
| Message-ID | <14ea840a-b27e-49c3-99b0-edebbb020662n@googlegroups.com> |
| In reply to | #174657 |
On Saturday, 9 September 2023 at 01:52:30 UTC+1, Ben Bacarisse wrote:
> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>
> > int sign(double x)
> > {
> > if (x < 0) return -1;
> > if (x == 0) retun 0;
> > if (x > 0) return 1;
> > /* unreachable */
> > }
> Just for information...
> > In fact sign() needs to return a double to handle the corner case properly.
> >
> > It's NaN of course. The sign of NaN is NaN.
> In IEEE floating point (almost universal these days) NaNs (and
> infinities) are signed, and the sign often carries useful information.
> You can't just state that "the sign of NaN is NaN" as if it's a plain
> fact. One might want, for example, something more like:
>
> return x == 0 ? 0 : 1 - 2*signbit(x);
>
> The information alluded to above being that some readers may not know
> that C has a signbit macro.
>
IEEE also allows for signed zero. But the sign of zero is zero. Certainly for
positive zero. I suppose you might argue that for the rare negative zeroes
you should return -1.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2023-09-09 21:31 +0100 |
| Message-ID | <87y1hfks06.fsf@bsb.me.uk> |
| In reply to | #174663 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
> On Saturday, 9 September 2023 at 01:52:30 UTC+1, Ben Bacarisse wrote:
>> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>>
>> > int sign(double x)
>> > {
>> > if (x < 0) return -1;
>> > if (x == 0) retun 0;
>> > if (x > 0) return 1;
>> > /* unreachable */
>> > }
>> Just for information...
>> > In fact sign() needs to return a double to handle the corner case properly.
>> >
>> > It's NaN of course. The sign of NaN is NaN.
>> In IEEE floating point (almost universal these days) NaNs (and
>> infinities) are signed, and the sign often carries useful information.
>> You can't just state that "the sign of NaN is NaN" as if it's a plain
>> fact. One might want, for example, something more like:
>>
>> return x == 0 ? 0 : 1 - 2*signbit(x);
>>
>> The information alluded to above being that some readers may not know
>> that C has a signbit macro.
>>
> IEEE also allows for signed zero. But the sign of zero is zero. Certainly for
> positive zero. I suppose you might argue that for the rare negative zeroes
> you should return -1.
One might argue that, yes. But I decided to try to make minimal changes
to the behaviour of the posted code. The hypothetical author appears to
want positive and negative zeros to have sign(...) == 0.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-09-10 12:03 +0200 |
| Message-ID | <udk4a5$hkp5$1@dont-email.me> |
| In reply to | #174644 |
On 09/09/2023 01:06, Malcolm McLean wrote:
> On Friday, 8 September 2023 at 15:03:51 UTC+1, David Brown wrote:
>> On 08/09/2023 11:47, Malcolm McLean wrote:
>>
>>> So a defined behaviour fallback is potentially useful. "This can't happen,
>>> but if it does, give me this diagnostic".
>> Where did you learn about logic? From watching Monty Python?
>>
>> Things that can't happen, can't happen. If the thing /might/ happen,
>> then it /can/ happen.
>>
>> Do you think I write my code by guesswork? Do you think I say to
>> myself, "I guess this is unlikely, and I don't want to consider it -
>> we'll pretend it it's impossible and tell the compiler its unreachable.
>> I'm sure no one will notice" ?
>>
> OK so
>
> int sign(double x)
> {
> if (x < 0) return -1;
> if (x == 0) retun 0;
> if (x > 0) return 1;
> /* unreachable */
> }
>
> Yes?
No :
// Precondition - "x" is a finite real-value double
// Postcondition - the return value is an integer -1, 0 or 1
// matching the sign of "x".
int sign(double x)
{
if (x < 0) return -1;
if (x == 0) return 0;
if (x > 0) return 1;
unreachable();
}
> No. In David Brown world, no-one would ever make that mistake.
I assume you are talking about double values that are unordered with
respect to 0, rather than your typo. Most people /do/ make typos like
this on occasion, but their editor or IDE would pick up on it
immediately - and their compiler would certainly spot it. I recommend
that you get a spell-checker for your Usenet client - it would pick up
on your regular typos. (I would make many more mistakes without a
spell-checker.)
You should write "unreachable();" to show that the line cannot be
reached by your code, as used in your program. If it might be reached,
don't write "unreachable();" - write the correct code to handle the
situation.
You seem to be under the strange misconception that some kind of omitted
or default behaviour is acceptable here. If "sign" is called with a NaN
or other value that is unordered with 0, then there is no plausible
correct value to return. A default "return 0;" would be wrong. Having
no return statement, so that in practice an unspecified value is
returned, is also wrong.
Writing "unreachable();" does not give a correct answer if someone fails
to follow the precondition for calling this function - but it makes it
clear to the reader and to the compiler that this line cannot be reached
when the function is used correctly. That is better than leaving a
mysterious and uninformed incorrect behaviour if the function is used
incorrectly.
> In reality,
> it's the sort of thing that is quite likely to slip through.
Not in my world, no. To me, programming is about specifying behaviour
and writing implementations of those specifications. It is certainly
the case that some specifications and details are never properly
documented, but they exist nonetheless. It seems entirely clear to me
that the function "sign" will be specified to work on real numbers, not
NaNs, because they do not have a sign.
> In fact sign() needs
> to return a double to handle the corner case properly.
No, it does not.
If you want to specify a function that takes a double and returns -1, 0,
1 or NaN if the argument does not have a sign, then you can do that -
calling the function "sign" would be a very bad name.
>
> It's NaN of course. The sign of NaN is NaN.
> Or you could say that NaN isn't in the domain of the function and either catch
> it, or just ignore it and accept any garbage - the real bug will be upstream.
You are beginning, slowly, to understand a little about the fundamentals
of programming. A function needs a specification. It has
pre-conditions, saying what must be true before the function starts. It
has post-conditions, saying what the function establishes when it is
finished. It has invariants, which are things that are true before it
starts, and remain true when it is finished. This gives you the
specification of the function.
Specifications are contracts - as the caller of the function, you
promise to fulfil the pre-conditions. The implementer of the function
then promises to fulfil the post-conditions. Stick to the contract, and
everyone is happy - lie and break the contract, and you have no reason
to expect anything.
Now, no one has given a clear specification of this "sign" function - we
have the name, and we can guess the specification from the name and the
original implementation. The pre-condition is that the argument is a
value that is ordered with respect to 0. The post-condition is an
integer -1, 0, or 1 representing that order with 0.
If that is the correct specification, then the implementation is
correct. The final line can be "unreachable();", "return 42;", omitted
entirely, or anything else - it's all fine. The sensible choice that is
clearest to the reader and gives the compiler the best chance for
optimisation and static error checking is "unreachable();".
If you want to change the specification and have a different function,
that's fine - and then you have a different implementation.
> Or you could say that the code is unreachable because we always filter
> out NaN. But how would you prove that?
>
Don't give the function a NaN in the first place.
None of my programs ever generate NaNs, and never have to deal with
them. I realise that some kinds of coding find NaNs, infinities, and
other non-real floating point values to be useful, but I don't. You are
only going to see them in some pretty odd and unusual calculations, so
take them into consideration at that point in your code.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-09-10 21:36 -0700 |
| Message-ID | <8238a0d7-aeb2-4b26-8b1d-611caa37049an@googlegroups.com> |
| In reply to | #174821 |
On Sunday, 10 September 2023 at 11:04:05 UTC+1, David Brown wrote: > On 09/09/2023 01:06, Malcolm McLean wrote: > > Or you could say that the code is unreachable because we always filter > > out NaN. But how would you prove that? > > > > Don't give the function a NaN in the first place. > > None of my programs ever generate NaNs, and never have to deal with > them. I realise that some kinds of coding find NaNs, infinities, and > other non-real floating point values to be useful, but I don't. You are > only going to see them in some pretty odd and unusual calculations, so > take them into consideration at that point in your code. > You see this is the typical "I don't need a seatbelt because I would never crash, and if you want a seatbelt then that means you shouldn't be driving" David Brown. Of course it's almost certainly a programming error to pass a NaN to sign(). And of course in simple programs, you can often easily show that NaNs will never occur. In a program which isn't simple, you would have to go through every call to sign(), and prove that a NaN can't be passed to it. Which isn't going to be practical. NaNs may well be passed to sign(), and the unreachable() statement may be executed. Now of course if we realise this, we shouldn't use "unreachable()". We should handle it. If maybe we don't realise this, unreachable() should be our seatbelt. You need methods which are as robust as possible to the errors which inevitably occur.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-09-11 08:51 +0200 |
| Message-ID | <udmddn$v4e7$1@dont-email.me> |
| In reply to | #174949 |
On 11/09/2023 06:36, Malcolm McLean wrote: > On Sunday, 10 September 2023 at 11:04:05 UTC+1, David Brown wrote: >> On 09/09/2023 01:06, Malcolm McLean wrote: >>> Or you could say that the code is unreachable because we always filter >>> out NaN. But how would you prove that? >>> >> >> Don't give the function a NaN in the first place. >> >> None of my programs ever generate NaNs, and never have to deal with >> them. I realise that some kinds of coding find NaNs, infinities, and >> other non-real floating point values to be useful, but I don't. You are >> only going to see them in some pretty odd and unusual calculations, so >> take them into consideration at that point in your code. >> > You see this is the typical "I don't need a seatbelt because I would > never crash, and if you want a seatbelt then that means you > shouldn't be driving" David Brown. Bollocks. I mean, complete and under drivel. Maybe this is news to you, but some programmers know what they are doing. Some of us understand good software development practices, and apply them appropriately. It is /peanuts/ to write floating point code that does not have NaNs. You simply don't get them in straightforward code. And you don't get them in complicated code either, unless you specifically choose to write code that lets error conditions build up because it is more efficient to do lots of calculations and check for oddities (NaNs, infinities, etc.) afterwards. You are the one that is always telling people that floating point numbers represent real quantities - distances, times, weights, whatever. These don't have NaNs, and anything you do with them is not going to give you a NaN. And in /my/ code, specifically, floating point types always represent real quantities. And NaNs, infinities, and other special cases do not ever occur. Would you like to explain where you get NaNs in your code, or think you might get them, and not know perfectly well that they are a possibility in that particular section of the code? > > Of course it's almost certainly a programming error to pass a NaN to > sign(). Yes. If you want a "sign_or_NaN" function, write that and use it when you need it. It's a different function, with a different domain, and a different specification. > And of course in simple programs, you can often easily show > that NaNs will never occur. In a program which isn't simple, you would > have to go through every call to sign(), and prove that a NaN can't be > passed to it. Which isn't going to be practical. That is simply terrible programming practice. Seriously. You should know about the data that you are dealing with at any point in the code. NaNs represent errors - they can be a practical error management method for some code (especially looped or vectored calculations where throughput per clock cycle is important), but like any other error, they should be contained to a small and manageable part of the code - not leaked everywhere. So you know when your floating point data could be a NaN or not - and if it could be, you don't call sign() with it. In fact, you usually don't do much for it except check it for validity before moving on. > > NaNs may well be passed to sign(), and the unreachable() statement > may be executed. Now of course if we realise this, we shouldn't use > "unreachable()". We should handle it. If maybe we don't realise this, > unreachable() should be our seatbelt. No, what you are describing there is a drunk driver in a Ferrari driving at 200 mph on a busy mountain road, wondering if a seatbelt is a good idea. To get in the situation you describe, you have to make a whole range of appallingly bad design, specification and coding issues. This is not the result of bugs in coding (these happen to everyone, and as has been discussed, there are ways to help find bugs). This is the result of bad project leadership or bad management. > > You need methods which are as robust as possible to the errors which > inevitably occur. You need methods to find and fix bugs that occur - programmers make mistakes, and these bugs need to be found. That I agree on. What you don't need, is ways that cover up bugs and pass them on down the line. You don't want programmers to have the attitude that it doesn't really matter if your function is wrong and gives the wrong answers, as the caller function expects wrong answers and will pass the buck elsewhere. Take some responsibility for writing /correct/ code!
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2023-09-10 23:59 -0700 |
| Message-ID | <udmdte$uh79$10@dont-email.me> |
| In reply to | #174963 |
On 9/10/2023 11:51 PM, David Brown wrote: > On 11/09/2023 06:36, Malcolm McLean wrote: >> On Sunday, 10 September 2023 at 11:04:05 UTC+1, David Brown wrote: >>> On 09/09/2023 01:06, Malcolm McLean wrote: >>>> Or you could say that the code is unreachable because we always filter >>>> out NaN. But how would you prove that? >>>> >>> >>> Don't give the function a NaN in the first place. >>> >>> None of my programs ever generate NaNs, and never have to deal with >>> them. I realise that some kinds of coding find NaNs, infinities, and >>> other non-real floating point values to be useful, but I don't. You are >>> only going to see them in some pretty odd and unusual calculations, so >>> take them into consideration at that point in your code. >>> >> You see this is the typical "I don't need a seatbelt because I would >> never crash, and if you want a seatbelt then that means you >> shouldn't be driving" David Brown. > > Bollocks. I mean, complete and under drivel. > > Maybe this is news to you, but some programmers know what they are > doing. Some of us understand good software development practices, and > apply them appropriately.[...] :^) C and C++ allows us to eat without putting corks on the forks... This scene in dirty rotten scoundrels still cracks me up: https://youtu.be/SKDX-qJaJ08 Why is the cork on the fork? To prevent him from hurting himself. This reminds me of people saying that C and/or C++ are to dangerous. Still makes me giggle.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-09-11 01:01 -0700 |
| Message-ID | <2ead0d9a-bc68-48c6-8fba-f10756997a6an@googlegroups.com> |
| In reply to | #174963 |
On Monday, 11 September 2023 at 07:51:50 UTC+1, David Brown wrote: > On 11/09/2023 06:36, Malcolm McLean wrote: > > It is /peanuts/ to write floating point code that does not have NaNs. > You simply don't get them in straightforward code. And you don't get > them in complicated code either, unless you specifically choose to write > code that lets error conditions build up because it is more efficient to > do lots of calculations and check for oddities (NaNs, infinities, etc.) > afterwards. > For your code, maybe. > > You are the one that is always telling people that floating point > numbers represent real quantities - distances, times, weights, whatever. > These don't have NaNs, and anything you do with them is not going to > give you a NaN. > Vaild data shouldn't have NaNs. However sometimes you have missing values. Sometimes it is incorrectly assumed that that data will not have missing values, which is one way you can get a NaN. Of course you'll say that you shouldn't incorrectly assume that data which can have missing values can't have missing values. In your world. > > And in /my/ code, specifically, floating point types always represent > real quantities. And NaNs, infinities, and other special cases do not > ever occur. > > Would you like to explain where you get NaNs in your code, or think you > might get them, and not know perfectly well that they are a possibility > in that particular section of the code? > Degenerate geometry, bascially. An example of degenerate geometry is a quad which is actually a triangle because one of its sides is of zero length. But there are many, many possible degeneracies. Because the calculations and done with finite precision, there are also near-degeneracies which cause the same problems. Its virtually inevitable that occasionally a check for a degeneracy will be either missed or set to a too low an episilon. And because the degeneracies are often rare, it can take a long time for the error to actually manifest itself. That's the main. way that NaNs crop up unexpectly in my code. You seem to think that your own, highly supervised, highly controlled environment which deals only with understood problems, is the way everyone has to work. In my case, the costs of errors aren't very high (the worst thing that can happen is that someone's drawing gets ruined, which is embarrassing for the company, but it's not like we'll be hit with lawsuit for killing a baby). And a lot of the algorithms are novel - no one has ever written a function to achieve a the same transformation before. And the criteria for acceptability are often "does it look OK?" and hard to specify mathematically. So bascially what I want is a system that is robust to the inevitable programming errors. It should return incorrect results rather than crashing out, because usually the user can simply press "undo" an an operation hasn't worked, but his work is still there. But it should also ideally tell me what has gone wrong and where.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-09-11 11:17 +0200 |
| Message-ID | <udmlvm$10ckq$1@dont-email.me> |
| In reply to | #174965 |
On 11/09/2023 10:01, Malcolm McLean wrote: > On Monday, 11 September 2023 at 07:51:50 UTC+1, David Brown wrote: >> On 11/09/2023 06:36, Malcolm McLean wrote: >> >> It is /peanuts/ to write floating point code that does not have NaNs. >> You simply don't get them in straightforward code. And you don't get >> them in complicated code either, unless you specifically choose to write >> code that lets error conditions build up because it is more efficient to >> do lots of calculations and check for oddities (NaNs, infinities, etc.) >> afterwards. >> > For your code, maybe. I don't believe there is anything special about my code in this respect. >> >> You are the one that is always telling people that floating point >> numbers represent real quantities - distances, times, weights, whatever. >> These don't have NaNs, and anything you do with them is not going to >> give you a NaN. >> > Vaild data shouldn't have NaNs. Correct. And you should not be using potentially invalid data without knowing that it is potentially invalid. > However sometimes you have missing values. That may be the case. But you don't fill in the missing values with random bits - you deal with them appropriately (which will depend on the application). So missing values are not a source of NaNs, unless the application and algorithms mean it is sensible to use NaNs to fill in the missing values. And if that's the case, you know it is the case. > Sometimes it is incorrectly assumed that that data will not have missing values, > which is one way you can get a NaN. And there's the root of your problem - incorrect assumptions. I don't know where you'd get such incorrect assumptions - perhaps from poor specifications, or poor names for your functions, or poor testing, or poor code reviews. > Of course you'll say that you shouldn't incorrectly assume that data which can > have missing values can't have missing values. In your world. If programmers are making incorrect assumptions about the data, and the code, then they have a far bigger problem than just an odd "unreachable()" statement. I appreciate that some software is written by incompetent programmers (from lack of training, lack of experience, lack of leadership, lack of time, whatever). And you have to deal with that in some way. But strangling good software is not the way to do it. Data comes in two forms. Verified data, that you know is correct (valid, in range, free from SQL injection attacks, etc.), and unverified data that comes from unknown or untrusted outside sources. The boundary between these can be data read from files or received from networks, or it can be a public API for a library, or different modules of a program written by different programming groups. Sometimes you put in temporary boundaries and verifications, for debugging, testing and fault-finding. Sometimes security concerns mean you have to add extra internal boundaries and checks. But in general, once data is verified and moved "inside" your code, /you/ have full control and full responsibility. It doesn't go missing. It doesn't acquire NaNs mysteriously. If functions are not well specified, it is /your/ fault. If functions are not used according to specification, it is /your/ fault. (Specifications don't have to be formally written to be important.) And if you've made a mistake - such as data not been fully verified - you have to fix that mistake. Crippling internal functions so that they are inefficient and functionally useless is not the answer. Nor is intentionally going out of your way to pass the errors around. >> >> And in /my/ code, specifically, floating point types always represent >> real quantities. And NaNs, infinities, and other special cases do not >> ever occur. >> >> Would you like to explain where you get NaNs in your code, or think you >> might get them, and not know perfectly well that they are a possibility >> in that particular section of the code? >> > Degenerate geometry, bascially. An example of degenerate geometry is a > quad which is actually a triangle because one of its sides is of zero length. So check for it. > But there are many, many possible degeneracies. Because the calculations > and done with finite precision, there are also near-degeneracies which > cause the same problems. So do the calculations, then check for NaN or other problems, then deal with those issues. Don't pass on crap data to the rest of the code. And if you are getting these kinds of issues, you need to look a lot harder at your algorithms. Making good numerical algorithms that are stable in face of awkward data like this is not easy. If you are not qualified to do it, find someone who is (or more likely, find an existing library that does the job right). > Its virtually inevitable that occasionally a check for a degeneracy will be > either missed or set to a too low an episilon. And because the degeneracies are > often rare, it can take a long time for the error to actually manifest itself. > > That's the main. way that NaNs crop up unexpectly in my code. If you know they can crop up, they are not unexpected - and you should deal with them at the time. > > You seem to think that your own, highly supervised, highly controlled > environment which deals only with understood problems, is the way everyone > has to work. Have you ever heard of "divide and conquer" ? Break up your problems until you have something small enough that it can be controlled and understood. I appreciate that NaNs can turn up in some kinds of code - I said that several times already. The flaw is letting them escape thoughtlessly. > In my case, the costs of errors aren't very high (the worst thing that can happen > is that someone's drawing gets ruined, which is embarrassing for the company, > but it's not like we'll be hit with lawsuit for killing a baby). And a lot of the algorithms > are novel - no one has ever written a function to achieve a the same transformation > before. And the criteria for acceptability are often "does it look OK?" and hard to > specify mathematically. > > So bascially what I want is a system that is robust to the inevitable programming > errors. It should return incorrect results rather than crashing out, because usually > the user can simply press "undo" an an operation hasn't worked, but his work is > still there. But it should also ideally tell me what has gone wrong and where. > All I am saying is that you take responsibility of your code, and its results. If you consider NaN an appropriate result, fair enough - deal with it. Don't expect other code that handles finite values to be changed to give meaningless results just because you want to pass in meaningless arguments.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-09-11 03:16 -0700 |
| Message-ID | <0cea903b-f004-4fb5-aae4-b6263e553e74n@googlegroups.com> |
| In reply to | #174976 |
On Monday, 11 September 2023 at 10:17:58 UTC+1, David Brown wrote: > On 11/09/2023 10:01, Malcolm McLean wrote: > > > Degenerate geometry, bascially. An example of degenerate geometry is a > > quad which is actually a triangle because one of its sides is of zero length. > So check for it. > You are just mouthing platitudes as if they were great insights, and arrogantly presenting them as your superior wisdom. So you seriously think that if it was as simple as "check for it" I wouldn't have thought of that? Seriously? .
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-09-11 14:58 +0200 |
| Message-ID | <udn2u8$12b7a$1@dont-email.me> |
| In reply to | #174980 |
On 11/09/2023 12:16, Malcolm McLean wrote: > On Monday, 11 September 2023 at 10:17:58 UTC+1, David Brown wrote: >> On 11/09/2023 10:01, Malcolm McLean wrote: >> >>> Degenerate geometry, bascially. An example of degenerate geometry is a >>> quad which is actually a triangle because one of its sides is of zero length. >> So check for it. >> > You are just mouthing platitudes as if they were great insights, and arrogantly > presenting them as your superior wisdom. > So you seriously think that if it was as simple as "check for it" I wouldn't have > thought of that? Seriously? > . From what you are saying, yes. Seriously. From what you have said before about matrix determinants, I know you don't have a lot of knowledge or experience in numerical methods and algorithms. (There's nothing wrong with that - no one can be experienced in everything.) So do I think you might have a geometry algorithm in your code that is numerically unstable? Absolutely - certainly if your application can tolerate some visual glitches (in such cases, an occasionally unstable algorithm might be better than a more complex stable algorithm). And do I think you are lax about checking? Yes - you've said as much. I know different kinds of software require different levels of development quality. You need to put a lot more effort into ensuring the correctness of code that will be in a card buried in a oil well head at the bottom of the ocean than you need for a computer game that can be easily updated online. But I like to believe that most programmers are interested in writing correct code. So if your data might be invalid, you check it. If your data might not fit within the domain of the function you want to call, you check it. If your function might not be able to return correct results, your function needs to return error indicators in some way, so that the caller function knows what it is getting. And then the caller function handles the errors. What you don't do is leave the problem data wandering around your program, ready to cause more trouble. You don't cripple the performance by writing all functions so that they handle NaNs in some predictable way - you make sure they are not called with NaNs. You specify your functions - including whether they can accept NaNs and what range of valid data they accept, and what range of valid data and/or NaNs they return. That all makes your code easier to write, lets you have more efficient functions, keeps it cleaner, makes it easier to analyse (so that you know when your data is valid), and makes it easier to debug. No one said this was simple. Perhaps "check the data" is hard in your case. Sometimes programming /is/ hard.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-09-11 06:35 -0700 |
| Message-ID | <120791af-c99c-4fd8-8017-016f19038d8fn@googlegroups.com> |
| In reply to | #175014 |
On Monday, 11 September 2023 at 13:59:03 UTC+1, David Brown wrote:
> On 11/09/2023 12:16, Malcolm McLean wrote:
> > On Monday, 11 September 2023 at 10:17:58 UTC+1, David Brown wrote:
> >> On 11/09/2023 10:01, Malcolm McLean wrote:
> >>
> >>> Degenerate geometry, bascially. An example of degenerate geometry is a
> >>> quad which is actually a triangle because one of its sides is of zero length.
> >> So check for it.
> >>
> > You are just mouthing platitudes as if they were great insights, and arrogantly
> > presenting them as your superior wisdom.
> > So you seriously think that if it was as simple as "check for it" I wouldn't have
> > thought of that? Seriously?
> > .
> From what you are saying, yes. Seriously.
>
> From what you have said before about matrix determinants, I know you
> don't have a lot of knowledge or experience in numerical methods and
> algorithms. (There's nothing wrong with that - no one can be
> experienced in everything.) So do I think you might have a geometry
> algorithm in your code that is numerically unstable? Absolutely -
> certainly if your application can tolerate some visual glitches (in such
> cases, an occasionally unstable algorithm might be better than a more
> complex stable algorithm). And do I think you are lax about checking?
> Yes - you've said as much.
>
> I know different kinds of software require different levels of
> development quality. You need to put a lot more effort into ensuring
> the correctness of code that will be in a card buried in a oil well head
> at the bottom of the ocean than you need for a computer game that can be
> easily updated online. But I like to believe that most programmers are
> interested in writing correct code.
>
> So if your data might be invalid, you check it. If your data might not
> fit within the domain of the function you want to call, you check it.
> If your function might not be able to return correct results, your
> function needs to return error indicators in some way, so that the
> caller function knows what it is getting. And then the caller function
> handles the errors.
>
> What you don't do is leave the problem data wandering around your
> program, ready to cause more trouble. You don't cripple the performance
> by writing all functions so that they handle NaNs in some predictable
> way - you make sure they are not called with NaNs. You specify your
> functions - including whether they can accept NaNs and what range of
> valid data they accept, and what range of valid data and/or NaNs they
> return. That all makes your code easier to write, lets you have more
> efficient functions, keeps it cleaner, makes it easier to analyse (so
> that you know when your data is valid), and makes it easier to debug.
>
> No one said this was simple. Perhaps "check the data" is hard in your
> case. Sometimes programming /is/ hard.
>
No. But the point is that this function
double lengthSQ(Vector *v)
{
return v->x *v->x + v->y *v->y;
}
will return NaN if v has a NaN member. And it might well be the case that
the person who wrote it is completely ignorant that IEEE floating points have
a NaN representation.
And that's typical. Most operations on NaN return NaN, so most functions are
correct within the domain of NaN.
Now this function
int sign(double x)
{
if (x < 0) return -1;
if (x == 0) return 0;
if (x > 0) return 1;
}
is an exception. Control will fall off the end if we pass NaN. And because we've returned the
sign as an int, we have no NaN representation. So it's not correct for NaN. And that's a bit
unusual.
Now if we make it double valued and "return x" instead of falling off the brace, we won't "cripple
performance". But there might be a slight perfomance impact. Is it worthwhile? Hard to
say. But there's definitely a case for it. It just depends what the consequences of getting things
incorrect are. And, as you say, probably if you are passing NaN to sign() that indicates a
programming error upstream anyway.
But checking for every possible degeneracy that could cause a NaN in geometrical algorithms
is hard, and sometimes unacceptably expensive. And degenerate doesn't always mean "invalid".
For instance a quad with a zero-length side is still clockwise or anti-clockwise. However you
can't tell which by taking a wedge product of two adjacent sides, if one of them is the zero
length side.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-11 14:13 +0000 |
| Message-ID | <20230911070056.703@kylheku.com> |
| In reply to | #175022 |
On 2023-09-11, Malcolm McLean <malcolm.arthur.mclean@gmail.com> wrote:
> Now this function
>
> int sign(double x)
> {
> if (x < 0) return -1;
> if (x == 0) return 0;
> if (x > 0) return 1;
> }
>
> is an exception. Control will fall off the end if we pass NaN. And because we've returned the
> sign as an int, we have no NaN representation. So it's not correct for NaN.
We could write it like this:
{
if (x < 0) return -1;
if (x > 0) return 1;
return 0;
}
Then in the reference manual we add the admonishment: "If the input is
NaN, then sign returns 0; a NaN input is not converted to a NaN output,
since the return type has no such representation. The application should
check the argument for NaN in situations where that is necessary."
The zero return is correct for NaN because we defined it that way;
it means that the input is neither positive nor negative, not
that it's a number.
This is the same like defining pow(0, 0) to be 1, etc.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-09-11 16:24 +0200 |
| Message-ID | <udn7vg$136e1$1@dont-email.me> |
| In reply to | #175022 |
On 11/09/2023 15:35, Malcolm McLean wrote:
> On Monday, 11 September 2023 at 13:59:03 UTC+1, David Brown wrote:
>> On 11/09/2023 12:16, Malcolm McLean wrote:
>>> On Monday, 11 September 2023 at 10:17:58 UTC+1, David Brown wrote:
>>>> On 11/09/2023 10:01, Malcolm McLean wrote:
>>>>
>>>>> Degenerate geometry, bascially. An example of degenerate geometry is a
>>>>> quad which is actually a triangle because one of its sides is of zero length.
>>>> So check for it.
>>>>
>>> You are just mouthing platitudes as if they were great insights, and arrogantly
>>> presenting them as your superior wisdom.
>>> So you seriously think that if it was as simple as "check for it" I wouldn't have
>>> thought of that? Seriously?
>>> .
>> From what you are saying, yes. Seriously.
>>
>> From what you have said before about matrix determinants, I know you
>> don't have a lot of knowledge or experience in numerical methods and
>> algorithms. (There's nothing wrong with that - no one can be
>> experienced in everything.) So do I think you might have a geometry
>> algorithm in your code that is numerically unstable? Absolutely -
>> certainly if your application can tolerate some visual glitches (in such
>> cases, an occasionally unstable algorithm might be better than a more
>> complex stable algorithm). And do I think you are lax about checking?
>> Yes - you've said as much.
>>
>> I know different kinds of software require different levels of
>> development quality. You need to put a lot more effort into ensuring
>> the correctness of code that will be in a card buried in a oil well head
>> at the bottom of the ocean than you need for a computer game that can be
>> easily updated online. But I like to believe that most programmers are
>> interested in writing correct code.
>>
>> So if your data might be invalid, you check it. If your data might not
>> fit within the domain of the function you want to call, you check it.
>> If your function might not be able to return correct results, your
>> function needs to return error indicators in some way, so that the
>> caller function knows what it is getting. And then the caller function
>> handles the errors.
>>
>> What you don't do is leave the problem data wandering around your
>> program, ready to cause more trouble. You don't cripple the performance
>> by writing all functions so that they handle NaNs in some predictable
>> way - you make sure they are not called with NaNs. You specify your
>> functions - including whether they can accept NaNs and what range of
>> valid data they accept, and what range of valid data and/or NaNs they
>> return. That all makes your code easier to write, lets you have more
>> efficient functions, keeps it cleaner, makes it easier to analyse (so
>> that you know when your data is valid), and makes it easier to debug.
>>
>> No one said this was simple. Perhaps "check the data" is hard in your
>> case. Sometimes programming /is/ hard.
>>
> No. But the point is that this function
>
> double lengthSQ(Vector *v)
> {
> return v->x *v->x + v->y *v->y;
> }
>
> will return NaN if v has a NaN member. And it might well be the case that
> the person who wrote it is completely ignorant that IEEE floating points have
> a NaN representation.
> And that's typical. Most operations on NaN return NaN, so most functions are
> correct within the domain of NaN.
Okay. So that function is "NaN propagating" - that's common for
functions that operate on real numbers and return real numbers.
>
> Now this function
>
> int sign(double x)
> {
> if (x < 0) return -1;
> if (x == 0) return 0;
> if (x > 0) return 1;
> }
>
> is an exception. Control will fall off the end if we pass NaN. And because we've returned the
> sign as an int, we have no NaN representation. So it's not correct for NaN. And that's a bit
> unusual.
It is not at all unusual. This is not a calculation function, it is a
classification function, operating on finite numbers and returning an
integer.
If that's not what you want, use or write a different function.
>
> Now if we make it double valued and "return x" instead of falling off the brace, we won't "cripple
> performance". But there might be a slight perfomance impact.
The impact on the performance is dependent on the way the code is used -
a function like this will typically be inlined. "Cripple" may be too
strong a word - it may also be too weak.
> Is it worthwhile? Hard to
> say.
Agreed.
But it won't give you the sign of the argument when passed a NaN, and so
the name would be wrong.
> But there's definitely a case for it. It just depends what the consequences of getting things
> incorrect are.
I am usually much more interested in encouraging correct coding than
worrying about the consequences of incorrect coding. Sometimes the
consequences of incorrect coding need to be the focus, such as in
security-critical code. But most often, you are better off spending the
effort getting the code right than minimising the consequences of
getting it wrong.
And code that does not do what it says, or does not say what it does, is
encouraging incorrect coding.
> And, as you say, probably if you are passing NaN to sign() that indicates a
> programming error upstream anyway.
Yes. So concentrate on that, not on the function that is correct.
>
> But checking for every possible degeneracy that could cause a NaN in geometrical algorithms
> is hard, and sometimes unacceptably expensive. And degenerate doesn't always mean "invalid".
> For instance a quad with a zero-length side is still clockwise or anti-clockwise. However you
> can't tell which by taking a wedge product of two adjacent sides, if one of them is the zero
> length side.
>
If that is an issue, then perhaps you have the wrong data structure.
Maybe you should store additional information (such as the orientation)
along with the points. Maybe you should be using different formats for
your points, such as quaternions instead of three real dimensions.
Maybe you should take care to order your quads so that any zero-length
sides come last, or split one side in two so that your sides all have
non-zero length. Or change your orientation function's algorithm to
find the most numerically stable choice of sides and use that for
determining the orientation.
There are many possibilities, and the "best" will of course be a
trade-off, and of course depend on how you are using the data.
[toc] | [prev] | [next] | [standalone]
Page 2 of 7 — ← Prev page 1 [2] 3 4 5 6 7 Next page →
Back to top | Article view | comp.lang.c
csiph-web