base 1p1

57 views
Skip to first unread message

Raul Miller

unread,
Feb 11, 2026, 7:18:33 PM (2 days ago) Feb 11
to J Programming Forum
1p1b10.220122021121110301000010110010
4
1p1b_30.121201110022130012030022212122
_10


How would you write a verb antibase where arguments like

1p1 antibase 4

would produce a result like

'10.220122021121110301000010110010'

Thanks,

--
Raul

Helen

unread,
Feb 12, 2026, 12:16:54 AM (yesterday) Feb 12
to forum, Raul Miller
I went with a quotient-remainder algorithm that calculates the first 30 decimal places. There's an explicit version, and if you're like me and love terribly long tacit verbs, there's one of those too!

If you want to use these for very large arrays, please do note they are not particularly optimised, but hopefully they will provide a starting point if that is a direction you want to go. Note also the "0, these verbs assume both x and y are a single atom (and the "0 hopefully helps prevent accidental misuse).

antibase=:{{
exponent=.<.x ^. y
numstr=.''
for_i. i.30 do.
  quot=.<.y % x ^ (exponent - i)
  y=.y |~ x ^ (exponent - i)
  numstr=.numstr , ":quot
  if. 0 = exponent - i do.
    numstr=.numstr , '.'
  end.
end.
if. '.' = {:numstr do.
  numstr=.}:numstr
end.
numstr
}}"0

antibase=:([:}:^:('.'={:)>:@<.@^.(({.,'.',}.)[:;@:(<@":@<.)}:)((_2&}.@:],((<:@:{:@],~{.@](<.@:%,|~)[^{:@])_2{.]))^:30],(<.@:^.)))"0

Kind regards,
Helen

Raul Miller

unread,
Feb 12, 2026, 1:35:03 AM (yesterday) Feb 12
to Helen, forum
Hmm... clever. (The implementation I threw together when thinking
about this is a long form implementation, by the way).

That said, I should have included some more test cases:

1p3 antibase 256
87.tdssa5gri
1p1 antibase 0
0
1x1 antibase _8
_22.1110111021020120010102001100211112

Or something close to that - a slightly shorter or longer
representation might not be a problem. But I'd limit the precision of
the result to the precision of the implied floating point
representation:

1p3b87.tdssa5gri
256
256-1p3b87.tdssa5gri
0
datatype 1p3b87.tdssa5gri
floating

Also, I am not overly concerned about rank on this one (since the
result is intended to be a sequence of characters, so using something
like antibase&.> would probably need to be a thing when applying it to
an array of arguments).

Thanks,

--
Raul

Helen

unread,
Feb 12, 2026, 3:36:38 PM (21 hours ago) Feb 12
to forum, Raul Miller, forum, Helen
Aha! Thank you for the extra testcases, they were very helpful in trying to get rid of edge cases and drawbacks with the verb.
With some more careful writing I've arrived at the following, which tries to work out the shortest string that yields exactly y:

digits=:(,":"+i.10) , (a. {~ 97+i.26)

antibase=:{{

'base (x) should be greater than 1 and no more than 36' assert (>&1*.<:&36) x

sign=.'_' #~ (y < 0)

target=.y=.|y

maxexp=.0 >. <.x ^. y

xstr=.":!.40 x

numstr=.''

for_exp. maxexp - i.50 do.

if. 0 >:!.0 target - (". ::0 xstr,'b',numstr) do. break. end.

  'quot y'=.y (<.@:%;|~) x ^ exp

  numstr=.numstr , (quot { digits)

  if. 0 = exp do.

    numstr=.numstr , '.'

  end.

end.

if. '.' = {:numstr do.

  numstr=.}:numstr

end.

sign , numstr

}}"0


There's a few tricks used here to avoid edge cases and having to keep track of the value of the approximation ourselves. There's also a lot I could mention that you may want to change, but I think the most important thing to note is that you could replace the for-if combination with a while loop. As long as you remember to initialise exp to start at maxexp, and then decrement it each iteration, the loop should always terminate. However, I am rather wary of unchecked loops, so I set an upper bound of 50 iterations. (Of course you can also change that upper bound to whatever number would be most appropriate.)

There do seem to be some weird cases where a "perfect" approximation isn't found. For example,
   1x1 antibase 1.3

1.0201111212000000121011020010202112110

   1.3 - 1x1b1.020111121200000012101102001020211211    NB. without the trailing 0

2.22045e_16

   1.3 - 1x1b1.0201111212000000121011020010202112110  NB. adding back the trailing 0 changes the result(!)

_2.22045e_16


I'm afraid I have no clue what's happening here.

Either way, I've had good fun coming up with a solution for this; I may try to turn it into a tacit at some point!


Kind regards,

Helen

Raul Miller

unread,
Feb 12, 2026, 4:42:24 PM (20 hours ago) Feb 12
to Helen, forum
For what it's worth, my test implementation works on precision rather
than accuracy.

In other words:
<:2x^53
9007199254740991
<.1x1%:9007199254740991
36

For base 1x1 I would compute 36 digits of the value, if an integer
result is not adequate (then discarding any trailing zeros). (And I
can't be smarter about cases where the integer part is longer than 36
digits because J's 'b' notation does not support exponents to the
right of the 'b'.)

It just so happens that the first examples I tried turned out to have
no error. The error creeps in because floating point numbers can only
approximate many numbers.

I should maybe use >. instead of <. in that calculation, but I have
not noticed any case where that change would improve the result.

--
Raul

Arnab Chakraborty

unread,
1:46 AM (11 hours ago) 1:46 AM
to fo...@jsoftware.com
Dear all, 

   Jandroid used to be available as a readymade apk. I do not seem to be able to find the link anymore. Any idea?

Thanks and regards,

Arnab

To unsubscribe from this group and stop receiving emails from it, send an email to forum+un...@jsoftware.com.

Paul Jackson

unread,
2:04 AM (11 hours ago) 2:04 AM
to fo...@jsoftware.com

Arnab Chakraborty

unread,
10:25 AM (3 hours ago) 10:25 AM
to fo...@jsoftware.com
Thanks

Thanks and regards,

Arnab
Reply all
Reply to author
Forward
0 new messages