From: Amavect <amavect@gmail.com>
To: 9front@9front.org
Subject: Re: [9front] Re: seq: fix infinite loop
Date: Fri, 20 Aug 2021 20:30:54 -0500 [thread overview]
Message-ID: <20210820203054.69d9bed5@spruce.localdomain> (raw)
In-Reply-To: <YRrlnTa3XgX1bb1o@alice>
[-- Attachment #1: Type: text/plain, Size: 1470 bytes --]
On Mon, 16 Aug 2021 15:24:29 -0700
Anthony Martin <ality@pbrane.org> wrote:
> But really, if you're playing games at the boundaries
> of floating point precision, you're bound to lose. I
> suggest we either a) do nothing and leave the loop
> exactly as it is described in the manual but add a note
> in the BUGS section, or b) go back to the v8 method
> that calculates the number of steps in the loop before
> executing it. Even with the latter method you can see
> odd results due to precision limitations but at least
> there will be no infinite loops.
>
> I vote for "a".
I vote for 'b', at the toss of a coin.
I've spent some time bikeshedding this sickly program, and attached is
the sickly result.
It does neat things like `seq -w 003` printing out 001, 002, 003.
It probably shouldn't do that, though.
It also doesn't use exponential notation to print out numbers.
This allows seq to not be limited from -999999 to 999999.
Even still, the result doesn't feel quite right.
Implementing a floating point number parser in seq is weird.
Invalid number combinations cause it to crash.
The following does not print out 0.3 in either implementation:
seq 0.1 0.1 0.3
The only way to correctly print out decimals is by nesting seq:
for(i in `{seq 0 9}) for(j in `{seq -w 0 9}) echo $i.$j
Therefore, I propose replacing floating point with integers.
If we're lucky, seq can count decimals using integers.
We can also implement hexadecimal counting.
Thanks,
Amavect
[-- Attachment #2: seq.c --]
[-- Type: text/x-c++src, Size: 2691 bytes --]
#include <u.h>
#include <libc.h>
#include <ctype.h>
double first = 1.0;
double last = 0.0;
double step = 1.0;
double nsteps = 0.0;
double final = 0.0;
int constant;
int consigned;
char *format;
char *zarg;
char *sstep;
void
usage(void)
{
fprint(2, "usage: %s [-w] [-fformat] [first [step]] last\n", argv0);
exits("usage");
}
/*
* [+-]?(([0-9]+([.][0-9]*)?)|([.][0-9]+))([Ee][+-]?[0-9]+)?
*/
void
getwidths(char *s, int *mh, int *mt)
{
int h, t, e, m;
h = 0;
t = 0;
m = 0;
if(*s == '+' || *s == '-'){
s++;
m++;
}
if(isdigit(*s)){
s++;
h++;
while(isdigit(*s)){
s++;
h++;
}
if(*s == '.'){
s++;
while(isdigit(*s)){
s++;
t++;
}
}
}else if(*s == '.'){
s++;
if(!isdigit(*s++))
goto out;
while(isdigit(*s)){
s++;
t++;
}
}else
goto out;
if(*s|32 == 'e'){
s++;
e = atoi(s);
if(e > 307)
e = 307;
if(e < -30)
e = -30;
h += e;
t -= e;
}
out:
if(h <= 0)
h = 1 + m;
if(t < 0)
t = 0;
if(h > *mh)
*mh = h;
if(t > *mt)
*mt = t;
return;
}
int
headwidth(double d)
{
int i;
i = 1;
if(d < 0.0){
d = -d;
i++;
}
if(d > 1.0)
i += log10(d);
return i;
}
void
buildfmt(void)
{
int h, t, z;
static char fmt[16];
h = 0;
t = 0;
/* determine head and tail widths from bounds and increment */
getwidths(zarg, &h, &t);
if(sstep)
getwidths(sstep, &z, &t);
z = headwidth(final);
if(z > h)
h = z;
if(constant){
if(t > 0)
h += t + 1;
if(first < 0.0 || last < 0.0){
consigned = 1;
sprint(fmt, "%%+%d.%df\n", h, t);
}else
sprint(fmt, "%%%d.%df\n", h, t);
}else
sprint(fmt, "%%.%df\n", t);
format = fmt;
}
void
main(int argc, char *argv[]){
int j, n;
char buf[512], ffmt[4096];
double val, i, preval;
ARGBEGIN{
case 'w':
if(format)
sysfatal("-w incompatible with -f");
constant++;
break;
case 'f':
if(constant)
sysfatal("-f incompatible with -w");
format = EARGF(usage());
if(format[strlen(format)-1] != '\n'){
sprint(ffmt, "%s\n", format);
format = ffmt;
}
break;
default:
goto out;
}ARGEND
out:
if(argc<1 || argc>3)
usage();
last = atof(argv[argc-1]);
if(argc > 1)
first = atof(argv[0]);
if(argc > 2){
sstep = argv[1];
step = atof(argv[1]);
}
if(step == 0.0)
sysfatal("zero increment");
nsteps = (last - first) / step;
final = floor(nsteps) * step + first;
zarg = argv[0];
if(!format)
buildfmt();
preval = step + first;
for(i = 0; i <= nsteps; i++){
val = i * step + first;
n = sprint(buf, format, val);
if(constant){
for(j = 0; buf[j] == ' '; j++)
buf[j] = '0';
if(consigned && j > 0){
buf[0] = buf[j];
buf[j] = '0';
}
}
write(1, buf, n);
preval = val;
}
exits(0);
}
next prev parent reply other threads:[~2021-08-21 1:55 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-15 22:02 [9front] " Sean Hinchee
2021-08-16 21:45 ` Amavect
2021-08-18 22:53 ` Eckard Brauer
2021-08-16 22:24 ` [9front] " Anthony Martin
2021-08-16 23:38 ` ori
2021-08-17 2:15 ` hiro
2021-08-21 1:30 ` Amavect [this message]
2021-08-18 2:49 ` [9front] " ori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210820203054.69d9bed5@spruce.localdomain \
--to=amavect@gmail.com \
--cc=9front@9front.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).