Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[Inform] Using Inform to port BASIC programs

13 views
Skip to first unread message

Muffy St. Bernard

unread,
Oct 31, 2000, 2:38:06 PM10/31/00
to
Hello!

A few months ago, all the talk in here about David Ahl's "Basic
Computer Games" got me all nostalgic. Back home in my parents attic,
what did I find -- fate! -- but both of Ahl's books, sitting there and
waiting to be implemented into Inform. (I also found my old "Making
Adventure Games for Your Computer" book by whatsisname, the book with
"Werewolves & Wanderer" etc. in it, but that's another story).
I understand that both Wumpus & Camel have been ported to Inform (or
is the correct term "Z-Code?") by members of this list -- thanks! I'd
like to spread the joy a bit more by doing the same thing for other
programs in the books. This presents a number of challenges, but after
just a few hours hacking away at them I've come away with an increased
knowledge of how Inform works, at least.
Some things I am wondering (and feel free to contact me privately at
muf...@hotmail.com, if you feel it's off-topic):
1) Is Inform/Z-Code perfect for this sort of task, or is it limited?
I can get around the lack of 2-dimensional arrays, but how about the
lack of decimals? There are ways around that, but are they crippling?
How about making string arrays (the good old BASIC A$(x) structure)
which seems like a heck of a bother? (I know, nobody said it would be
easy).
2) Are there better programming manuals out there than the Designer's
Manual? One unconcerned with the Inform Library, that would be more use
for porting BASIC programs?
3) Are there sample .inf files out there for ported BASIC programs?
I've looked in the archives, but can't seem to find any. Having a
sample would help a lot when I get stuck.
4) Does anybody have a favourite they'd like to see ported?
"Seabattle" maybe? "Convoy?" I've picked "Black Box" as a
starter...but when it comes to those A$(x) variables -- ala Eliza, for
instance -- I might end up swearing off computers forever, cutting the
soles off my shoes, climbing a tree and learning to play the flute.

Any help is much appreciated!

Muffy.

Mark Musante - Sun Microsystems

unread,
Oct 31, 2000, 3:26:14 PM10/31/00
to
Muffy St. Bernard (muffy...@hotmail.com) wrote:
> "Seabattle" maybe? "Convoy?" I've picked "Black Box" as a
> starter...but when it comes to those A$(x) variables -- ala Eliza, for
> instance -- I might end up swearing off computers forever, cutting the
> soles off my shoes, climbing a tree and learning to play the flute.

If you want wacky string manipulation, use TADS.


-=- Mark -=-

Adam J. Thornton

unread,
Oct 31, 2000, 3:54:21 PM10/31/00
to
In article <39FF1F9E...@hotmail.com>,

Muffy St. Bernard <muffy...@hotmail.com> wrote:
> 4) Does anybody have a favourite they'd like to see ported?
>"Seabattle" maybe? "Convoy?" I've picked "Black Box" as a
>starter...but when it comes to those A$(x) variables -- ala Eliza, for
>instance -- I might end up swearing off computers forever, cutting the
>soles off my shoes, climbing a tree and learning to play the flute.

W. Top Changwatchai asked me to scan in Seabattle for him quite some
time ago, and I have been a lazy bum and not done it. So I'd recommend
you do Seabattle for him.

I'd reconsider your graduation plans, though. It really helps our side
if you re-enlist. Or at least find a bunch of guys who all dress alike
and follow them around.

What is reality?

Adam


--
ad...@princeton.edu
"My eyes say their prayers to her / Sailors ring her bell / Like a moth
mistakes a light bulb / For the moon and goes to hell." -- Tom Waits

Gadget

unread,
Oct 31, 2000, 5:33:10 PM10/31/00
to
On 31 Oct 2000 20:26:14 GMT, mmus...@Sun.COM (Mark Musante - Sun
Microsystems) made the world a better place by saying:

Is it me or does this sound a bit harsh? The man just wanted help on
programming inform, which is a powerful language. It's just more like
C then like basic. For example, the way the parser goes from word to
word is pure pointer stuff. But then again, you hardly need bother
with that since the lingo is purely object oriented.

My advice for starting on inform (as I did a couple of weeks ago) is
not to try to write basic in inform. I once tried this when I learned
C and it got me in a whole heap of trouble (with pointers and such),
because the languages are so different.

The best thing is, I think, to 'reverse engineer' the game and make a
new design doc, with a complete map and write down all the puzzles and
verbs the original game had. Then code the thing using Inform from
scratch. I think you will find that inform is then very easy to use.
Easier then basic when it comes to handling adventures (excuse me,
IF). Since most of the groundwork for the parser is already done, you
only have to deal with the gameworld and rules. The descriptions and
messages you can just use from the original and there you have it!

Ok, it will be difficult at first, but then, you are starting with
something big...

--
"So... you've compiled your own Kernel... Your skills are now complete..."
-----------------
It's a bird
It's a plane
No it's... Gadget?

HaHa Magazine: http://www.haha.demon.nl
To send E-mail: remove SPAMBLOCK from adress.

Ross Presser

unread,
Oct 31, 2000, 4:50:43 PM10/31/00
to
alt.distinguished."mmus...@Sun.COM (Mark Musante - Sun
Microsystems)".wrote.posted.offered:


Anyone ever thought of targeting a BASIC interpreter at the
Z-machine?

--
Ross Presser * ross_p...@imtek.com
A blank is ya know, like, a tab or a space. A name is like wow! a
sequence of ASCII letters, oh, baby, digits, like, or underscores,
fer shure, beginnin' with a letter or an underscore.

Carl Muckenhoupt

unread,
Oct 31, 2000, 6:19:30 PM10/31/00
to
On Tue, 31 Oct 2000 22:33:10 GMT, gad...@SPAMBLOCKhaha.demon.nl
(Gadget) wrote:

>On 31 Oct 2000 20:26:14 GMT, mmus...@Sun.COM (Mark Musante - Sun
>Microsystems) made the world a better place by saying:
>

>>If you want wacky string manipulation, use TADS.
>>
>>
>> -=- Mark -=-
>
>Is it me or does this sound a bit harsh?

Hardly. It's simply sound advice, analogous to "If you want wacky
string manipulation outside of an IF context, use perl" or "If you
want your code to run very very fast, use assembly language". TADS is
a powerful language too, and one area where it outshines Inform is in
string processing. It even has built-in regular expression functions.

-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----

mathew

unread,
Oct 31, 2000, 8:02:02 PM10/31/00
to
Carl Muckenhoupt <ca...@wurb.com> wrote:
> Hardly. It's simply sound advice, analogous to "If you want wacky
> string manipulation outside of an IF context, use perl" or "If you
> want your code to run very very fast, use assembly language".

I hate to be picky, as it's rather outside the scope of this newsgroup,
but the latter is very very oversimplistic advice, and unsound in many
circumstances.

A more accurate piece of advice would be "If you want your code to run
very very fast, profile it and write the critical bottleneck routines in
assembly language -- but only if you're a true expert, or you're using a
very simple CPU architecture, or you can't get a good optimizing
compiler."

An optimizing compiler will do better than an average human programmer
at writing assembler. On architectures where there are complex and
subtle behaviors such as delayed and speculative branch, heavy
pipelining and asynchronous parallel instruction execution, compilers
will do better than almost any human programmer for any non-trivial
piece of code.


mathew
--
No taxation without representation!

Larry Smith

unread,
Oct 31, 2000, 9:08:59 PM10/31/00
to

"Gadget" <gad...@SPAMBLOCKhaha.demon.nl> wrote in message
news:39ff37b2...@news.demon.nl...

> On 31 Oct 2000 20:26:14 GMT, mmus...@Sun.COM (Mark Musante - Sun
> Microsystems) made the world a better place by saying:

> The best thing is, I think, to 'reverse engineer' the game and make a


> new design doc, with a complete map and write down all the puzzles and
> verbs the original game had. Then code the thing using Inform from
> scratch. I think you will find that inform is then very easy to use.
> Easier then basic when it comes to handling adventures (excuse me,
> IF). Since most of the groundwork for the parser is already done, you
> only have to deal with the gameworld and rules. The descriptions and
> messages you can just use from the original and there you have it!

I echo this sentiment, but I'd like to phrase it in slightly different
terms.

Hundreds of years ago, people didn't have modern carpentry tools. And even
metal was rare, so entire houses were made without nails. This led to a lot
of extra effort. Some of it was ingenious, getting beams to interlock
securely by clever shaping of the pieces. Still, it was a lot more work than
is done today.

So suppose you were given the detailed specs for an old house. Would you
build it in exactly the same way today? Certainly you could, especially if
you were a history buff, and living in such a duplicate appealed to you. But
if what you want to do, mostly, is just get a nice roof over your head,
where you can live with your family in comfort, then you probably wouldn't
want to slavishly follow those original plans.

But, of course, that's what you're doing if you try to translate those old
Basic games as verbatim as is feasible into Inform / TADS / Hugo / etc.

Getting back to the subject of tools -- I'm certain that a *lot* of the
Basic code involved things that come for free with today's tools (Inform, et
al). The parser comes to mind, of course. And smaller things like moving
from room to room. Locking and unlocking doors. Handling lit and unlit
rooms. And so forth. Probably most of that is already taken care of. At
which point, how much Basic is left? Much, much less is my guess. Take away
all the text and room definitions (which will be done differently in Inform
et al), and you're left with even less.

At which point you're reduced to the puzzles and the interactions (maybe
there's a dwarf to duel with or something). And that's the heart of the
game. If it's a good game, that's what's important. It matters little if
it's implemented in Basic, Inform, or whatever. As Gadget said, extract the
essence of the game, understand it, and then see how to implement it using
modern tools. You'll probably have better success than with a blind
transliteration of one language into another.

Finally, as a tip, are there other ways to accomplish things? For example,
old Basic programs has significant space limitations. Maybe (and I'm
totally, totally guessing here), maybe some of the string manipulation
involved changing a lot of the descriptions of things once you watered the
Tree of Life (don't know the games, so I'm making stuff up here). But
another way to approach such a thing is to change the map dynamically. Have
two Tree of Life rooms, one before watering and one after (initially
unreachable), each with different descriptions, things in them, etc. Then
have the "water the xxx" verb move you (invisibly, behind the scenes) to the
new room. Or maybe the string manipulations were for something else
entirely. But the point here is that there may be alternate ways to
accomplish something that the original author did, and in significantly
easier ways, using features in the new systems that didn't exist in the old.


Magnus Olsson

unread,
Nov 1, 2000, 4:32:25 AM11/1/00
to
In article <39FF1F9E...@hotmail.com>,
Muffy St. Bernard <muffy...@hotmail.com> wrote:
> I understand that both Wumpus & Camel have been ported to Inform (or
>is the correct term "Z-Code?")

The correct term would be "Inform" , since the games were actually
ported to the Inform language. Z-code is the underlying machine
language of the Z-machine. You can port directly to Z-code as well,
without going through Inform, but that would be a lot more work.

> 1) Is Inform/Z-Code perfect for this sort of task, or is it limited?
>I can get around the lack of 2-dimensional arrays, but how about the
>lack of decimals? There are ways around that, but are they crippling?

Not crippling, just a lot of work.

>How about making string arrays (the good old BASIC A$(x) structure)
>which seems like a heck of a bother? (I know, nobody said it would be
>easy).

Somebody really should sit down and write a string manipulation
library (using stream 3, I suppose). Or has this already been done?

Floating-point arithmetic is a trickier case, in terms of difficulty
but mostly in terms of demand - I don't think very many adventure
games really need floating point.

If you're just porting old games from Basic, you might consider
changing the algorithms to use integers instead of real numbers (for
example, if a game represents probabilities as FP numbers between 0
and 1, and then does some random number stuff, you could instead
represent the probabilities as percentage numbers between 0 and
100). But then you might run into problems with Inform's 16-bit limit on
integers.

> 3) Are there sample .inf files out there for ported BASIC programs?
>I've looked in the archives, but can't seem to find any. Having a
>sample would help a lot when I get stuck.

The source for my port of Wumpus is in the archive at
ftp://ftp.gmd.de/if-archive/games/source/inform/wumpus.inf.

> 4) Does anybody have a favourite they'd like to see ported?
>"Seabattle" maybe? "Convoy?" I've picked "Black Box" as a
>starter...but when it comes to those A$(x) variables -- ala Eliza, for
>instance -- I might end up swearing off computers forever, cutting the
>soles off my shoes, climbing a tree and learning to play the flute.

You might be better off writing a Basic interpreter in Inform, so
you can run the games directly.


--
Magnus Olsson (m...@df.lth.se, m...@pobox.com)
------ http://www.pobox.com/~mol ------

Magnus Olsson

unread,
Nov 1, 2000, 4:42:19 AM11/1/00
to
In article <39ff37b2...@news.demon.nl>,

Gadget <gad...@SPAMBLOCKhaha.demon.nl> wrote:
>On 31 Oct 2000 20:26:14 GMT, mmus...@Sun.COM (Mark Musante - Sun
>Microsystems) made the world a better place by saying:
>
>>Muffy St. Bernard (muffy...@hotmail.com) wrote:
>>> "Seabattle" maybe? "Convoy?" I've picked "Black Box" as a
>>> starter...but when it comes to those A$(x) variables -- ala Eliza, for
>>> instance -- I might end up swearing off computers forever, cutting the
>>> soles off my shoes, climbing a tree and learning to play the flute.
>>
>>If you want wacky string manipulation, use TADS.
>
>Is it me or does this sound a bit harsh?

It sounded a bit dismissive, perhaps, but I don't think Mark meant it
that way - it's the usual thing with emotions not showing in a text-
only medium and so on.

> The man just wanted help on
>programming inform, which is a powerful language. It's just more like
>C then like basic.

The problem is that Inform lacks string-handling primitives and
floating-point numbers, both of which are present in Basic. Porting
code which is rich in strings and FP to Inform is a decidedly
non-trivial task. It has nothing to do with how C-like Inform is (in
fact, when it comes to strings, Inform is decidedly un-C-like).

>For example, the way the parser goes from word to
>word is pure pointer stuff.

That is irrelevant in the cases of Basic-like strings and FP.
That is, how do you translate things like

A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)

and

X = SQR(LOG(3.14 * Y))

to Inform?

>But then again, you hardly need bother
>with that since the lingo is purely object oriented.

Until somebody has written a class library that deals with the
low-level stuff of strings and FP, Muffy does need to bother with the
low-level details.

>My advice for starting on inform (as I did a couple of weeks ago) is
>not to try to write basic in inform.

That's sound advice, but it won't eliminate the problems of strings
and FP.

>The best thing is, I think, to 'reverse engineer' the game and make a
>new design doc, with a complete map and write down all the puzzles and
>verbs the original game had. Then code the thing using Inform from
>scratch.

This is basically (no pun intended) what I did with "Wumpus".

>I think you will find that inform is then very easy to use.
>Easier then basic when it comes to handling adventures (excuse me,
>IF). Since most of the groundwork for the parser is already done, you
>only have to deal with the gameworld and rules. The descriptions and
>messages you can just use from the original and there you have it!

I think you've missed the point: Muffy St. Bernard is not writing
adventure games, but porting existing *non-adventure* programs from
Basic to Inform. Inform's IF features won't be of much help in that
task, I'm afraid.

Gadget

unread,
Nov 1, 2000, 8:35:05 AM11/1/00
to
On 1 Nov 2000 09:42:19 GMT, m...@pobox.com (Magnus Olsson) wrote:


>The problem is that Inform lacks string-handling primitives and
>floating-point numbers, both of which are present in Basic. Porting
>code which is rich in strings and FP to Inform is a decidedly
>non-trivial task. It has nothing to do with how C-like Inform is (in
>fact, when it comes to strings, Inform is decidedly un-C-like).
>
>>For example, the way the parser goes from word to
>>word is pure pointer stuff.
>
>That is irrelevant in the cases of Basic-like strings and FP.
>That is, how do you translate things like
>
>A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)
>
>and
>
>X = SQR(LOG(3.14 * Y))
>
>to Inform?

I wouldn't know... You are right about those and considering your
point about him not porting IF, I agree with you this is no small
task, wich I couldn't solve now if I had to.

Muffy St. Bernard

unread,
Nov 1, 2000, 9:01:15 AM11/1/00
to
Larry Smith wrote:

[snip]


> But, of course, that's what you're doing if you try to translate those old
> Basic games as verbatim as is feasible into Inform / TADS / Hugo / etc.

[snip]

Aha...no, I'm not talking about converting old BASIC IF into
Inform...though I can see why somebody would want to do so. I'm just
talking about a series of computer programs published in the 70's by
Creative Computing, which a lot of people (including me) get teary-eyed
about, because we played them so much on our little (often very little)
personal computers. They're not IF...most of the listings are only
about 200 lines long (if that).
In this case, my plan is to slavishly reproduce the OUTPUT of the
games so they can be played on a Z-Interpreter, but not to necessarily
reproduce the BASIC code itself (which would be...well...insane and
pointless and probably impossible). After posting the last message, I
DID manage to find uncompiled examples of exactly what I'm trying to do
on the GMD: "Life.zip" and -- wonder of wonders! -- "Eliza.zip". Eliza
answers a lot of my questions about ways around Inform's string
processing...
Thanks, everybody, for your responses! "Blackbox" today, "Seabattle"
... well...maybe soon. :-)

Muffy.

Muffy St. Bernard

unread,
Nov 1, 2000, 9:23:43 AM11/1/00
to
"Muffy St. Bernard" wrote:
>
> Thanks, everybody, for your responses! "Blackbox" today, "Seabattle"
> ... well...maybe soon. :-)

And when I say "today" I mean...someday. It really is an
undertaking. Thank you, Magnus, for directing me to your wumpus.inf
file. It's terrifically elegant! Your examples of difficult code to
translate into Inform:

> A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)
>
> and
>
> X = SQR(LOG(3.14 * Y))

were a splash of cold water...jeez. And that rules out half of the
programs in the book (all of those dealing with trajectories and
duplicating physics problems, most of which I didn't find interesting to
play, fortunately).
Since winter is coming, this is a good time to warm up the computer,
experiment a bit, and see what I come up with.

Thanks!

Muffy.

Jake Wildstrom

unread,
Nov 1, 2000, 9:36:52 AM11/1/00
to
In article <3A00276F...@hotmail.com>,

Muffy St. Bernard <muffy...@hotmail.com> wrote:
> were a splash of cold water...jeez. And that rules out half of the
>programs in the book (all of those dealing with trajectories and
>duplicating physics problems, most of which I didn't find interesting to
>play, fortunately).

Ah, so we won't be porting "Artillery" to inform any time soon then, I suppose.

(besides, artillery used graphics generated on-the-fly, which I don't believe
Blorb can do yet)

+--First Church of Briantology--Order of the Holy Quaternion--+
| A mathematician is a device for turning coffee into |
| theorems. -Paul Erdos |
+-------------------------------------------------------------+
| Jake Wildstrom |
+-------------------------------------------------------------+

David Given

unread,
Nov 1, 2000, 6:17:25 AM11/1/00
to
In article <8FDEAE70...@209.155.56.91>,
rpre...@NOSPAMimtek.com.invalid (Ross Presser) writes:
[...]

> Anyone ever thought of targeting a BASIC interpreter at the
> Z-machine?

I've got a first draft C compiler port to the Z-machine tucked away
somewhere, if anyone's interested; and Gevan has one for the
Glulx-machine.

--
+- David Given ---------------McQ-+ "The time has come," Mithrandir said, "To
| Work: d...@tao-group.com | talk of many things: Of Moria, and bridges,
| Play: dgi...@iname.com | and deep fissures --- of Balrogs, and their
+- http://wired.st-and.ac.uk/~dg -+ wings." --- Meneldil on rasfw

Andrew Plotkin

unread,
Nov 1, 2000, 10:23:59 AM11/1/00
to
Magnus Olsson <m...@pobox.com> wrote:

> That is irrelevant in the cases of Basic-like strings and FP.
> That is, how do you translate things like
>
> A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)
>
> and
>
> X = SQR(LOG(3.14 * Y))
>
> to Inform?

There's a string-handling library for Inform. I believe it compiles
for Glulx too, which would work better, since Glulx is more flexible
both about strings and about dynamic memory allocation. (Which you
need for the A$ statement above. BASIC has dynamic memory allocation
built in at the language level, but that doesn't mean a library can't
do the same work.)

For floating point, well, either convert the code to fixed-point (or
some other representation), or use some other system. Does TADS have a
floating-point data type? Does it operate deterministically, or will
different implementations have different precisions?

--Z

"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the
borogoves..."

Magnus Olsson

unread,
Nov 1, 2000, 10:44:41 AM11/1/00
to
In article <97309222...@rexx.com>,

Andrew Plotkin <erky...@eblong.com> wrote:
>Magnus Olsson <m...@pobox.com> wrote:
>
>> That is irrelevant in the cases of Basic-like strings and FP.
>> That is, how do you translate things like
>>
>> A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)
>>
>> and
>>
>> X = SQR(LOG(3.14 * Y))
>>
>> to Inform?
>
>There's a string-handling library for Inform.

Excellent! I must confess to being a bit out of touch regarding the
Inform library additions.

I suppose this is good news for Muffy :-).

>for Glulx too, which would work better, since Glulx is more flexible
>both about strings and about dynamic memory allocation. (Which you
>need for the A$ statement above. BASIC has dynamic memory allocation
>built in at the language level, but that doesn't mean a library can't
>do the same work.)

I don't think it will be much trouble re-writing the Ahl games to
use pre-allocated strings of fixed length. I remember doing that
when porting the Eliza implementation from Ahl's book to the Acorn
Atom (whose Basic implemented strings in a way similar to C's, i.e.
as an interpretation of arrays of characters. I also had to write
string search routines in assembler for that port.)

>For floating point, well, either convert the code to fixed-point (or
>some other representation),

I suggested using fixed-point maths in an earlier post, but the problem
is the (very) limited precision offered by Inform's 16-bit integers.
And when the code contains transcendental functions such as sin and log
the proting is decidedly non-trivial (taking the square root of a
fixed-point number is easy; taking the sine isn't).

> or use some other system. Does TADS have a
>floating-point data type?

AFAIK, it doesn't.

Have you ever thought about adding FP to Glulx?

ical...@my-deja.com

unread,
Nov 1, 2000, 11:14:18 AM11/1/00
to
In article <8tonv9$b33$1...@news.lth.se>,
m...@pobox.com (Magnus Olsson) wrote:

> Floating-point arithmetic is a trickier case, in terms of difficulty
> but mostly in terms of demand - I don't think very many adventure
> games really need floating point.

It would sure make the implementation of money easier. Dangerous
Curves' money-handling routines were labyrinthine, to say the least.

irene


Sent via Deja.com http://www.deja.com/
Before you buy.

Andrew Plotkin

unread,
Nov 1, 2000, 11:31:48 AM11/1/00
to
Magnus Olsson <m...@pobox.com> wrote:
>> or use some other system. Does TADS have a
>>floating-point data type?
>
> AFAIK, it doesn't.
>
> Have you ever thought about adding FP to Glulx?

Yes, and then I could never think of a reason to do it.

(Irene Callaci just mentioned money. I've been assuming that money
only requires integer math, where at worst you store monetary values
as integral number of cents instead of fractional number of dollars.
Is this not sufficient?)

(I'll note that in the actual-money-handling credit card software I
write for my day job, we use integer math in pennies!)

To use FP math in Glulx would require specifying a storage
representation. Preferably 32 bits, given the system architecture.
Icky.

Richard Bos

unread,
Nov 1, 2000, 11:53:05 AM11/1/00
to
"Muffy St. Bernard" <muffy...@hotmail.com> wrote:

> > A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)
> >
> > and
> >
> > X = SQR(LOG(3.14 * Y))
>
> were a splash of cold water...jeez. And that rules out half of the
> programs in the book (all of those dealing with trajectories and
> duplicating physics problems, most of which I didn't find interesting to
> play, fortunately).

Not really; you can, with a bit of dirty hacking, replace floating point
maths by fixed point. It's awkward, but it might be a solution.

Richard

Kaia Vintr

unread,
Nov 1, 2000, 12:15:51 PM11/1/00
to
Andrew Plotkin wrote in message <9730962...@rexx.com>...

>To use FP math in Glulx would require specifying a storage
>representation. Preferably 32 bits, given the system architecture.
>Icky.
>

Not as icky as trying to work around the limitation. IMO it would be much
more work to write (and debug) a library that implements fractional
calculations using integers or strings than it would be to add this
functionality to (a given) v-machine. Yes, portability is an issue, but I
think most architectures implement the IEEE standards, and there's plenty of
public-domain source code to use for those that don't. If you'd like some
help...

- Kaia

ems...@my-deja.com

unread,
Nov 1, 2000, 12:14:38 PM11/1/00
to
In article <9730962...@rexx.com>,

Andrew Plotkin <erky...@eblong.com> wrote:
> Magnus Olsson <m...@pobox.com> wrote:
> > Have you ever thought about adding FP to Glulx?
>
> Yes, and then I could never think of a reason to do it.
>
> (Irene Callaci just mentioned money. I've been assuming that money
> only requires integer math, where at worst you store monetary values
> as integral number of cents instead of fractional number of dollars.
> Is this not sufficient?)

Should be, unless you do a new improved Bank of Zork that compounds
interest.

The only place where this has come up for me is in trying to do
divisible and miscible liquids with multiple container sizes. But I've
still mostly been able to do what I wanted to do using large integers:
the difference is there, but not anything that a real live player would
be likely to notice.

Anyway, none of that will see the light of day until/unless I figure
out how to fix the parsing problems. So.

ES

David Given

unread,
Nov 1, 2000, 11:25:30 AM11/1/00
to
In article <3A00276F...@hotmail.com>,

"Muffy St. Bernard" <muffy...@hotmail.com> writes:
> "Muffy St. Bernard" wrote:
>>
>> Thanks, everybody, for your responses! "Blackbox" today, "Seabattle"
>> ... well...maybe soon. :-)
>
> And when I say "today" I mean...someday. It really is an
> undertaking. Thank you, Magnus, for directing me to your wumpus.inf
> file. It's terrifically elegant! Your examples of difficult code to
> translate into Inform:
>
>> A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)

Inform string handling is like C. I'd do something like:

char* foo(char* bstring)
{
int len = strlen(bstring);
char* astring = malloc(len*3); /* maximum length of output */

strcpy(astring, bstring);
strcat(astring, " foo ");
{
char* p = astring + strlen(astring);
*p++ = bstring[len - 3];
*p = '\0';
}
return astring;
}

Ouch.

And as for the floating point code... well, the only way I can
realistically think of doing that is to use 8.8 fixed point arithmetic and
lookup tables for the hard stuff. The accuracy would be pathetic.

--
+- David Given ---------------McQ-+

| Work: d...@tao-group.com | "Ignore reality. There's nothing you can
| Play: dgi...@iname.com | do about it." --- Natalie Imbruglia
+- http://wired.st-and.ac.uk/~dg -+

Muffy St. Bernard

unread,
Nov 1, 2000, 2:03:57 PM11/1/00
to
David Given wrote:
>
> >> A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)
>
> Inform string handling is like C. I'd do something like:

> (snip!)

> Ouch.

I think I've gone blind. It's almost overwhelming.
It does look like that's the sort of thing that will be necessary...



> And as for the floating point code... well, the only way I can
> realistically think of doing that is to use 8.8 fixed point arithmetic and
> lookup tables for the hard stuff. The accuracy would be pathetic.

I think that the only place where it would take a monumental amount of
work to get around it would be COS & SIN type calculations (which I
could never exactly comprehend anyway, even when a language was doing
them for me). This is why I'm ruling out trajectory games from the list
I might tackle (yes, sorry Artillery! And all those ones about two
objects flying at eachother...UFO...ICBM...)
After all of this, maybe I'll just write a Guess My Number game
instead. :-)

"PICK A NUMBER BETWEEN 1 AND 10, AND I WILL TRY TO GUESS IT!

MY GUESS IS 5

PRESS 1 FOR HIGHER, 2 FOR LOWER, OR 3 FOR CORRECT? "

No string handling! No FP calculations!

No fun.

Muffy.

Paul E. Bell

unread,
Nov 1, 2000, 5:29:12 PM11/1/00
to
Hi,

I don't know how relevant this will be, but, if you know C, and can
translate from C to Inform, you might look into the Fractint source
code, which, though it now uses floating point, it's main routines use
integer math.

Just a suggestion.

Paul

--
Paul E. Bell | Email and AIM: wd0...@millcomm.com | ifMUD: Helios
IRC: PKodon, DrWho4, and Helios | webpage: members.nbci.com/wd0gcp/
Member: W.A.R.N., Skywarn, ARES, Phoenix Developer Consortium, ...
_____ Pen Name/Arts & Crafts signature:
| | _ \ _ _ |/ _ _(
| | (_X (_/`/\ (_) (_` |\(_) (_) (_|_) (/`
)

lysseus

unread,
Nov 1, 2000, 5:22:06 PM11/1/00
to
"Andrew Plotkin" <erky...@eblong.com> wrote in message
news:97309222...@rexx.com...

> For floating point, well, either convert the code to fixed-point (or
> some other representation), or use some other system. Does TADS have a
> floating-point data type? Does it operate deterministically, or will
> different implementations have different precisions?

The following is from the TADS 3 BigNumber implementation documentaion,
which may be of interest to those working with complex calculations:

The BigNumber Intrinsic Class
-------------------------------
TADS 2 provided only integer arithmetic. While this was largely adequate
for writing interactive fiction, the need nonetheless arises on occasion for
more powerful arithmetic features than integer math provides, particularly
floating point values (numbers involving a fractional part), greater numeric
range (the ability to represent very large or very small numbers), and
greater precision (the ability to represent fine differences between
values). In adventure game programming, it is usually possible to simulate
these effects using integer arithmetic only, but this is considerably more
work than it would be with a more powerful math package.

TADS 3 addresses this occasional need with a new intrinsic class called
BigNumber, which provides high- precision floating-point arithmetic.
BigNumber can represent values very precisely, with up to 65,000 decimal
digits stored in a value; and can represent a huge range of values, with
absolute values up to 1032,767 and down to 10-32,767. These limits are so
high that, for all practical purposes, calculations will never encounter
them. Furthermore, the BigNumber class can store values with whatever
precision is required for each particular value, up to the limits, so a
program can specify the balance it requires between numerical precision and
performance (for reasons that are probably obvious, the more precision a
number stores, the more memory it uses and the more time it takes to perform
calculations with the number).

Note that the BigNumber type is not the "double-precision" or IEEE floating
point type with which readers with a programming background will be
familiar. The BigNumber type is superior in many ways to double-precision
values:

· BigNumber is portable to any computer, and behaves exactly the
same way on every computer. Doubles tend to have subtle but sometimes
vexing variations from one computer to another.

· BigNumber uses a decimal rather than binary encoding, which means
that any value that one can write in a decimal format can be represented
exactly without rounding error. Many common decimal values turn into
repeating sequences when expressed in binary (much as 1/3 cannot be exactly
represented in decimal: the 3's repeat forever in 0.33333.). This can lead
to surprising results when rounding errors accumulate in calculations that,
to all appearances, should be exact.

· BigNumber allows for effectively unlimited precision and much
greater range than doubles, which have a fixed precision that cannot be
changed by the programmer. This allows, for example, calculations involving
very large integers, or precise calculations where very large and very small
values are combined.

One advantage of double-precision values is better performance, partly
because arithmetic is simpler with a fixed-precision type, but mostly
because doubles are implemented in hardware on many platforms; but this
seems an equitable trade, since the kinds of applications that require
high-speed numerics probably wouldn't find an ideal match in TADS anyway.

Working with BigNumber Values
You must include the system header file <bignum.h> in your source files to
use the BigNumber class. This file defines the BigNumber class interface.

To create a BigNumber value, use the new operator, passing the value for the
number either as an integer or as a character string. You can optionally
specify the precision to use for the value; if you don't specify a
precision, the system infers a precision from the value.

x = new BigNumber(100);
x = new BigNumber(100, 10); // set precision to 10 digits
y = new BigNumber('3.14159265');
z = new BigNumber('1.06e-30');
z = new BigNumber('1.06e-30', 8); // precision is 8 digits

If you specify a string value, you can use a decimal point, and you can also
use an 'E' to specify a base-ten exponent. So, the fourth value above
should be read as 1.06 x 10-30.

You can also create a BigNumber object simply by using a numeric constant
that contains a decimal point or an exponent (or both):

x = 1.075;

You can perform addition, subtraction, multiplication, division, and
negation on BigNumber values using the standard operators. You can also use
integer values with BigNumber values in calculations, although the BigNumber
value must always be the first operand in an expression involving both a
BigNumber and an integer.

x = y + z;
x = (y + z) * (y - z) / 2;

Similarly, you can compare BigNumber values using the normal comparison
operators:

if (x > y) ...

You can convert a BigNumber to a string using the toString() function in the
"tads-gen" intrinsic function set. You can exercise more control over
formatting using the formatString() method of the BigNumber class itself.

You can convert a BigNumber to a regular integer value using the toInteger()
function from the "tads-gen" function set. Note that toInteger() throws an
error if passed a BigNumber value that is too large to represent as a 32-bit
integer, which can store values from 2,147,483,647 to -2,147,483,647.
toInteger() rounds numbers with fractional parts to the nearest integer.

You cannot use operators other than those listed above with BigNumber
values. You cannot use a BigNumber as an operand for any of the bitwise
operators (&, |, ~). You also cannot use a BigNumber with the integer
modulo operator ("%"), but you can obtain similar functionality from the
divideBy() method.

You cannot use BigNumber values in function and method calls that require
integer arguments. You must explicitly convert a BigNumber value to an
integer with the toInteger() function if you want to pass it to a method or
function that takes an integer value; the compiler does not perform these
conversions for you automatically.

Because BigNumber values are, for most purposes, simply object references,
you can use them where you can use other objects; you can, for example,
store a BigNumber in a list, or assign it to an object property.

Compiler Support
Although BigNumber is not a native type in the T3 VM (it is simply an
intrinsic class, which plugs into the VM using the VM's type extension
mechanism), the TADS 3 compiler has some minimal support for the type. In
particular, the compiler recognizes BigNumber constant values in this
format:

[ digits ] . [ digits ] [ E|e [+|-] digits ]

In other words, the compiler recognizes any numeric constant that includes a
decimal point (a period) or an exponent (specified with an 'e' or 'E') as a
BigNumber constant. When you include a number in this format in your source
code, the compiler will automatically create and initialize a BigNumber
object for you with the given value. So, the following two statements are
equivalent:

x = new BigNumber('3.14159265');
y = 3.14159265;

The compiler uses the same rules as the new operator for parsing the
number's value and precision.

Note that the compiler does not currently perform constant folding on
BigNumber values. This means that expressions like the following will
result in a run-time calculation being performed:

#define PI 3.14159265
x = PI/4;
Intrinsic Class Methods
The BigNumber class provides a number of methods for manipulating values.
Note that all of the methods that perform calculations return new BigNumber
values. A BigNumber object's value is immutable once the object is created,
so all calculations performed on these objects return new objects
representing the result values.

Note that these functions are all methods called on a BigNumber object, so
to calculate the absolute value of a BigNumber value x, we would code this:

y = x.getAbs();

Some of the methods take an argument giving a value to be combined with the
target number. For example, to get the remainder of dividing 10 by 3, we'd
write this:

x = new BigNumber('10.0000');
y = new BigNumber('3.00000');
rem = x.divideBy(y)[2]; // second list item is remainder

arccosine() - returns the arccosine (the number whose cosine is this value),
as a value in radians, of the number. This function is mathematically
meaningful only for input values from -1 to +1; this function throws a
run-time exception if the input value is outside of this range.

arcsine() - returns the arcsine (the number whose sine is this value), as a
value in radians, of the number. This function is mathematically meaningful
only for input values from -1 to +1; this function throws a run-time
exception if the input value is outside of this range.

arctangent() - returns the arctangent (the number whose tangent is this
value), as a value in radians, of the number.

copySignFrom(x) - returns a number containing the same absolute value as
this number, but with the sign of x replacing the original value's sign.

cosh() - computes the hyperbolic cosine of the number and returns the
result.

cosine() - computes the trigonometric cosine of the number (interpreted as a
radian value) and returns the result. Refer to the description of sine()
for notes on how the input precision affects the calculation.

degreesToRadians() - converts the value from radians to degrees and returns
the number of degrees. This simply multiplies the value by (pi/180).

divideBy(x) - computes the integer quotient of dividing this number by x,
and returns a list with two elements. The first element is a BigNumber
value giving the integer quotient, and the second element is a BigNumber
value giving the remainder of the division, which is a number rem satisfying
the relationship dividend = quotient*divisor + remainder.

Note that the quotient returned from divideBy() is not necessarily equal to
the whole part of the result of the division ("/") operator applied to the
same values. If the precision of the result (which is, as with all
calculations, equal to the larger of the precisions of the operands) is
insufficient to represent exactly the integer quotient result, the quotient
returned from this function will be rounded differently from the quotient
returned by the division operator. The division operator always rounds its
result to the nearest

equalRound(num) - determine if this value is equal to num after rounding.
This is equivalent to the "==" operator if the numbers have the same
precision, but if one number is more precise than the other, this rounds the
more precise of the two values to the precision of the less precise value,
then compares the values. The "==" operator makes an exact comparison,
effectively extending the precision of the less precise value by adding
imaginary zeroes to the end of the number.

expE() - returns the result of raising e, the base of the natural logarithm,
to the power of this number.

formatString(maxDigits, flags?, wholePlaces?, fracDigits?, expDigits?,
leadFiller?) - Formats the number, returning a string with the result. All
of the arguments after maxDigits are optional.

maxDigits specifies the maximum number of digits to display in the formatted
number; this is an upper bound only, and doesn't force a minimum number of
digits. If necessary, the function uses scientific notation to make the
number fit in the requested number of digits.

wholePlaces specifies the minimum number of places to show before the
decimal point; if the number doesn't fill all of the requested places, the
function inserts leading spaces (before the sign character, if any).

fracDigits specifies the number of digits to display after the decimal
point. This specifies the maximum to display, and also the minimum; if the
number doesn't have enough digits to display, the method adds trailing zeroe
s, and if there are more digits than fracDigits allows, the method rounds
the value for display.

expDigits is the number of digits to display in the exponent; leading zeroes
are inserted if necessary to fill the requested number of places.

Each of wholePlaces, fracDigits, and expDigits can be specified as -1, which
tells the method to use the default value, which is simply the number of
digits actually needed for the respective parts.

leadFiller, if specified, gives a string that is used instead of spaces to
fill the beginning of the string, if required to satisfy the wholePlaces
argument. This argument is ignored if its value is nil. If a string value
is provided for this argument, the characters of the string are inserted,
one at a time, to fill out the wholePlaces requirement; if the end of the
string is reached before the full set of padding characters is inserted, the
function starts over again at the beginning of the string. For example, to
insert alternating asterisks and pound signs, you would specify '*#' for
this argument.

flags is a combination of the following bit-flag values (combined with the
bit-wise OR operator, '|'):

BIGNUM_SIGN - always show a sign character. Normally, if the number is
positive, the function omits the sign character. If this flag is specified,
a '+' sign is shown for a positive number.
BIGNUM_POS_SPACE - if the number is positive and this flag is set, the
function inserts a leading space. (If BIGNUM_SIGN is specified, this flag
is ignored.) This function can be used to ensure that positive and negative
numbers fill the same number of character positions, even when you don't
want to use a '+' sign with positive numbers.
BIGNUM_EXP - always show the number in exponential format (scientific
notation). If this is not included, the function shows the number without
an exponent if it will fit in maxDigits digits.
BIGNUM_EXP_SIGN - always show a sign in the exponent. If this is included,
a positive exponent will be shown with a '+' sign. This flag is ignored
unless an exponent is displayed (so specifying this flag doesn't force an
exponent to be displayed).
BIGNUM_LEADING_ZERO - always show a zero before the decimal point. This is
only important when the number's absolute value is between 0 and 1, and an
exponent isn't displayed; without this flag, no digits will precede the
decimal point for such values (so 0.25 would be formatted as simply '.25').
BIGNUM_POINT - always show a decimal point. If the number has no fractional
digits to display, and this flag is included, a trailing decimal point is
displayed. Without this flag, no decimal point is displayed if no digits
are displayed after the decimal point.
BIGNUM_COMMAS - show commas to set off thousands, millions, billions, and so
on. This flag has no effect if the number is shown in scientific notation.
Commas do not count against the maxDigits or wholePlaces limits. However,
commas do count for leading filler, which ensures that a column of numbers
formatted with filler and commas will line up properly.
BIGNUM_EUROSTYLE - use European-style formatting: use periods instead of
commas to set off thousands, millions, etc., and use a comma instead of a
period to indicate the decimal point.

getAbs() - returns a number containing the absolute value of this number.
(This function could be easily coded from a comparison and negation, but the
method implementation is more efficient.)

getCeil() - "ceiling": returns a number containing the least integer greater
than this number. For example, the ceiling of 2.2 is 3. Note that for
negative numbers, the least integer above a number has a smaller absolute
value, so the ceiling of -1.6 is -1.

getE(digits) - returns the value of e (the base of the natural logarithm) to
the given number of digits of precision. This is a static method, so you
can call this method directly on the BigNumber class itself:

x = BigNumber.getE(10);

The BigNumber class internally caches the value of e to the highest
precision calculated during the program's execution, so this routine only
needs to compute the value when it is called with a higher precision than
that of the cached value.

getFloor() - "floor": returns a number containing the greatest integer less
than this number.

getFraction() - returns a number containing only the fractional part of this
number (the digits after the decimal point).

getPi(digits) - returns the value of pi to the given number of digits of
precision. This is a static method, so you can call this method directly on
the BigNumber class itself:

x = BigNumber.getPi(10);

The BigNumber class internally caches the value of pi to the highest
precision calculated during the program's execution, so this routine only
needs to compute the value when it is called with a higher precision than
that of the cached value.

getPrecision() - returns the number of digits of precision that this number
stores. The return value is of type integer.

getScale() - returns a value of type integer giving the base-10 scale of
this number. If the return value is positive, it indicates the number of
digits before the decimal point in the decimal representation of the number.
If the return value is zero, it indicates that the number has no whole part,
and that the first digit after the decimal point is non-zero (so the number
is greater than or equal to 0.1, and less than 1.0). If the return value is
negative, it indicates that the number has no whole part, and gives the
number of digits of zeroes that immediately follow the decimal point before
the first non-zero digit. If the value of the number is exactly zero, the
return value is 1.

getWhole() - returns a number containing only the whole part of this number
(the digits before the decimal point).

isNegative() - returns true if the number is less than zero, nil if the
number is greater than or equal to zero.

log10() - returns the base-10 logarithm of the number.

logE() - returns the natural logarithm of the number. The logarithm of a
non-positive number is not a real number, so this function throws a run-time
exception if the number is less than or equal to zero.

negate() - returns a number containing the arithmetic negative of this
number.

radiansToDegrees() - converts the value from degrees to radians and returns
the number of radians. This simply multiplies the value by (180/pi).

raiseToPower(y) - computes the value of this number raised to the power y
and returns the result. If the value of the target number is negative, then
y must be an integer: if x < 0, we can rewrite xy as (-1) y (-x) y, and we
know that -x > 0 because x < 0. The result of raising -1 to a non-integer
exponent cannot be represented as a real number, hence this function throws
an error if the target number is negative. Note also that raising zero to
any power yields 1, and raising any value to the power 0 yields 1, but the
special case of 00 is mathematically undefined, so the function throws an
error for this case.

roundToDecimal(places) - returns a number rounded to the given number of
digits after the decimal point. The new number has the same precision as
this number, but all of the digits after the given number of places after
the decimal point will be set to zero, and the last surviving digit will be
rounded. If places is zero, this simply rounds the number to an integer.
If places is less than zero, this rounds the number to a power of ten:
roundToDecimal(-1) rounds to the nearest multiple of ten, roundToDecimal(-2)
rounds to the nearest multiple of 100, and so on. Note that the precision
of the result is the same as the precision of the original value; rounding
merely affects the value, not the stored precision.

scaleTen(x) - returns a new number containing the value of this number
scaled by 10x. If x is positive, this multiplies this number's value by ten
x times (so if x = 3, the result is this number's value times 1000). If x
is negative, this divides this number's value by ten x times. (This is more
efficient than explicitly multiplying by ten, because it simply adjusts the
number's internal scale factor.)

setPrecision(digits) - returns a new number with the same value as this
number but with the specified number of digits of precision. If digits is
higher than this number's precision, the new value is simply extended with
zeroes in the added trailing digits. If digits is lower than this number's
precision, the value is rounded to the given number of digits of precision.

sine() - computes the trigonometric sine of the number (interpreted as a
radian value) and returns the result.

Note that the input value must be expressed in radians. If you are working
in degrees, you can convert to radians by multiplying your degree values by
(pi/180), since 180 degress equals pi radians. For convenience, you can use
the degreesToRadians() function to perform this conversion.

Note also that this remainder calculation's precision is limited by the
precision of the original number itself, so a very large number with
insufficient precision to represent at least a few digits after the decimal
point (1.234e27, for example) will encounter a possibly significant amount
of rounding error, which will affect the accuracy of the result. This
should almost never be a problem in practice, because there is usually
little reason to compute angle values outside of plus or minus a few times
pi, but users should keep this in mind if they are using very large numbers
and the trigonometric functions yield unexpected or inaccurate results.

sinh() - computes the hyperbolic sine of the number and returns the result.

sqrt() - returns the square root of the number. If the number is negative,
this function throws a run-time exception.

tangent() - computes the trigonometric tangent of the number (interpreted as
a radian value) and returns the result. Refer to the description of sine()
for notes on how the input precision affects the calculation.

Note that the tangent of (2n+1)*pi/2, where n is any integer, (i.e., any odd
multiple of pi/2) is undefined, and that the limit approaching these values
is plus or minus infinity. The BigNumber class internally calculates the
tangent and the sine divided by the cosine, and as a result it is possible
to generate a divide-by-zero exception by evaluating the tangent at one of
these values. However, in most cases, because the input value cannot be
exactly an odd multiple of pi/2 (because it isn't even theoretically
possible to represent pi exactly with a finite number of decimal digits),
the tangent will return a number with a very large absolute value.

tanh() - computes the hyperbolic tangent of the number and returns the
result.

Precision and Scale
Each floating-point value that BigNumber represents has two important
attributes apart from its value: precision and scale. For the most part,
these are internal attributes that you can ignore; however, in certain
cases, it's useful to know how BigNumber uses these internally.

The scale of a BigNumber value is a multiplier that determines how large the
number really is. A BigNumber value stores a scale so that a very large or
very small number can be represented compactly, without storing all of the
digits that would be necessary to write out the number in decimal format.
This is the same idea as writing a number in scientific notation, which
represents a number as a value between 1 and 10 multiplied by ten raised to
a power; for example, we could write four hundred fifty billion as
450,000,000,000, or more compactly in scientific notation as 4.5e11 (the "e"
means "times ten to the power of the number that follows", so this means
"4.5 times 1011"; note that 1011 is one hundred billion). When we write a
number in scientific notation, we need only write the significant digits,
and can elide the trailing zeroes of a very large number. We can also use
scientific notation to write numbers with very small absolute values, by
using a negative exponent: 9.7e-9 is 9.7 times 10-9; 10-9 is 1/109, or one
one-billionth.

The precision of a BigNumber value is simply the number of decimal digits
that the value actually stores. A number's precision determines how many
distinct values it can have; the higher the precision, the more values it
can store, and hence the finer the distinctions it can make between adjacent
representable values. The precision is independent of the scale; if you
create a BigNumber value with only one digit of precision, it's not limited
to representing the values -9 through +9, because the scale can allow it
take on larger or smaller values. So, you can represent arbitrarily large
values regardless of a number's precision; however, the precision limits the
number of distinct values the number can represent, so, for example, with
one digit of precision, the next representable value after 8000 is 9000.

When you create a BigNumber value, you can explicitly assign it a precision
by passing a precision specifier to the constructor. If you don't specify a
precision, BigNumber will use a default precision. If you create a
BigNumber value from an integer, the default precision is 32 digits. If you
create a BigNumber value from a string, the precision is exactly enough to
store the value's significant digits. A significant digit is a non-zero
digit, or a zero that follows a non-zero digit. Here are some examples:

'0012' has two significant digits (the leading zeroes are ignored).
'1.2000' has five significant digits (the trailing zeroes are significant
because they follow non-zero digits).
'.00012' has two significant digits (the leading zeroes are ignored, even
though they follow the decimal point).
'000.00012' has two significant digits (leading zeroes are ignored, whether
they appear before or after the decimal point).
'1.00012' has six significant digits (the zeroes after the decimal point are
significant because they follow a non-zero digit).
'3.20e06' has three significant digits (the digits of the exponent, if
specified, are not relevant to the number's precision).

When you use numbers in calculations, the result is almost every case has
the same precision as the value operated upon; in the case of calculations
involving two or more operands, the result has precision equal to the
greatest of the precisions of the operands. For example, if you add a
number with three digits of precision to a number with eight digits of
precision, the result will have eight digits of precision. This has the
desirable effect of preserving the precision of your values in arithmetic,
so that the precision you choose for your input data values is carried
forward throughout your calculations. For example, consider this
calculation:

x = new BigNumber('3.1415');
y = new BigNumber('0.000111');
z = x + y;

The exact arithmetic value of this calculation would be 3.1416111, but this
is not the value that ends up in z, because the precision of the operands
limits the precision of the result. The precision of x is 5, because it is
created from a string with five significant digits. The precision of y is
3. The result of the addition will have a precision of 5, because that is
the larger of the two input precisions. So, the result value stored in z
will be 3.1416 - the additional two digits of y are dropped, because they
cannot be represented in the result value's 5 digits of precision.

Precision limitations are fairly intuitive when the precision lost is after
the decimal point, but note that digits can also be dropped before a decimal
point. Consider this calculation:

x = new BigNumber('7.25e3');
y = new BigNumber('122');
z = x + y;

The value of x is 7.25e3, or 7250; this value has three digits of precision.
The value of y also has three digits of precision. The exact result of the
calculation is 7372, but the value stored in z will be 7370: the last digit
of y is dropped because the result doesn't have enough precision to
represent it.

Note that calculations will in most cases round their result values when
they must drop precision from operand values. For example:

x = new BigNumber('7.25e3');
y = new BigNumber('127');
z = x + y;

The exact result would be 7377, but the value stored in z will be 7380: the
last digit of y is dropped, but the system rounds up the last digit retained
because the dropped digit is 5 or higher (in this case, 7).

Exorcising Parasitic Users
Apart from the obvious numerical applications, the BigNumber package can be
useful if your computer is taken over by a hostile, parasitic, pure-energy
life form capable of transferring itself between human and computer hosts.
A standard work-around for this type of infection is to command the computer
to calculate a transcendental number (pi, for example) to the last digit;
this so preoccupies the computer that the unwanted life form is unable to
get any CPU time and eventually.

While BigNumber doesn't provide a way of computing transcendental numbers
"to the last digit," you can still consume copious amounts of CPU time by
asking it to compute a value to a large finite number of digits, such as

x = BigNumber.getPi(512);

This will consume about twenty minutes on a Pentium III at 400 MHz. If the
parasitic entity is especially tenacious, or tries to shut down life
support, it might be necessary to go out to a thousand or so digits.

Note that this technique isn't effective against conventional computer
viruses, so users should ensure that the problem can't be addressed with
standard anti-virus software before attempting this solution.


--Kevin


Matthew T. Russotto

unread,
Nov 1, 2000, 11:45:23 AM11/1/00
to
In article <8tpdp9$gql$1...@news.lth.se>, Magnus Olsson <m...@pobox.com> wrote:
}
}I suggested using fixed-point maths in an earlier post, but the problem
}is the (very) limited precision offered by Inform's 16-bit integers.
}And when the code contains transcendental functions such as sin and log
}the proting is decidedly non-trivial (taking the square root of a
}fixed-point number is easy; taking the sine isn't).

Microsoft did floating point, sines, cosines, etc for BASIC in less
than 12K of 6502 (8-bit, not so much as a hardware multiply)
assembler; I hardly think that Inform running on a more powerful
virtual machine with a larger memory model is going to make it
impossible. However, if I were doing it I'd hack Inform to support an
FP representation behind the scenes rather than trying to do it all
with arrays.
--
Matthew T. Russotto russ...@pond.com
"Extremism in defense of liberty is no vice, and moderation in pursuit
of justice is no virtue."

Matthew T. Russotto

unread,
Nov 1, 2000, 11:47:58 AM11/1/00
to
In article <9730962...@rexx.com>,

Andrew Plotkin <erky...@eblong.com> wrote:
}Magnus Olsson <m...@pobox.com> wrote:
}>> or use some other system. Does TADS have a
}>>floating-point data type?
}>
}> AFAIK, it doesn't.
}>
}> Have you ever thought about adding FP to Glulx?
}
}Yes, and then I could never think of a reason to do it.
}
}(Irene Callaci just mentioned money. I've been assuming that money
}only requires integer math, where at worst you store monetary values
}as integral number of cents instead of fractional number of dollars.
}Is this not sufficient?)
}
}(I'll note that in the actual-money-handling credit card software I
}write for my day job, we use integer math in pennies!)

FP is often not used in finance because of the roundoff problem;
integers may overflow but they won't silently lose precision.

Besides, since money is fixed precision you don't need it -- integer
in pennies or mils is quite sufficient.

Matthew T. Russotto

unread,
Nov 1, 2000, 11:39:05 AM11/1/00
to
In article <1ejdtah.f1j3o7m7k3vyN%me...@pobox.com>,
mathew <me...@pobox.com> wrote:

}An optimizing compiler will do better than an average human programmer
}at writing assembler. On architectures where there are complex and
}subtle behaviors such as delayed and speculative branch, heavy
}pipelining and asynchronous parallel instruction execution, compilers
}will do better than almost any human programmer for any non-trivial
}piece of code.

However, it is on exactly such architectures where some human programmers
can seriously beat the compiler for non-trivial code. Particularly
since they may have the advantage of knowing more about the cache
architecture and the use of the code than the compiler.

Carl Muckenhoupt

unread,
Nov 1, 2000, 8:19:28 PM11/1/00
to
On Wed, 01 Nov 2000 16:39:05 GMT, russ...@wanda.vf.pond.com (Matthew
T. Russotto) wrote:

>However, it is on exactly such architectures where some human programmers
>can seriously beat the compiler for non-trivial code. Particularly
>since they may have the advantage of knowing more about the cache
>architecture and the use of the code than the compiler.

It's the matter of use that always made me skeptical about optimizing
compilers. For example, the last time I did any optimization at this
level, the target platform was a 486, which takes a couple cycles
longer to branch than to not branch, if you see what I mean. A human
can know which branch of the code will be executed more frequently,
and therefore whether to bz or bnz. A compiler can't.

I suppose the real lesson here is: If you want code that goes really
really fast, don't run it on a 486.

andre...@my-deja.com

unread,
Nov 1, 2000, 8:37:49 PM11/1/00
to
In article <8tpfgj$2tf$1...@nnrp1.deja.com>,

ical...@my-deja.com wrote:
> In article <8tonv9$b33$1...@news.lth.se>,
> m...@pobox.com (Magnus Olsson) wrote:
>
> > Floating-point arithmetic is a trickier case, in terms of difficulty
> > but mostly in terms of demand - I don't think very many adventure
> > games really need floating point.
>
> It would sure make the implementation of money easier. Dangerous
> Curves' money-handling routines were labyrinthine, to say the least.

I think that for money that 32-bit integers would be more useful than
floating-point arithmetic. Example:

You can store $26444.66 as:
dollars=26444;
cents=66;
in Inform but that gets hard. With 32-bit integers:
money=2644466;

If you have 32-bit unsigned integers you can get up to 4,000,000,000
cents that is $40,000,000.00 which is certainly enough.

Larry Smith

unread,
Nov 2, 2000, 1:11:28 AM11/2/00
to

"Matthew T. Russotto" <russ...@wanda.vf.pond.com> wrote in message
news:DMXL5.12281$mC.7...@monger.newsread.com...

> In article <8tpdp9$gql$1...@news.lth.se>, Magnus Olsson <m...@pobox.com>
wrote:

> However, if I were doing it I'd hack Inform to support an


> FP representation behind the scenes rather than trying to do it all
> with arrays.

Yeah, but presumably the programs Muffy's trying to port (I'm thinking of
"Artillery" especially, assuming it's what it sounds like) have a very
special property. Coordinates are assumed to be limited to (0,0) to (79,24).
So lookup tables could be precomputed in another language (even Basic).

If you were to shoot a shell at an angle of, say, 37 degrees, after one
clock tick (and thus one column to the right) it would have gone perhaps 1
grid element upwards. After 2, up 2. After 3, still up 2. After 4 up 3. And
so on.

Assuming whole degrees is adequate resolution, you could encode this into a
2-D array of 91 rows (one each for 0..90 degrees, with 91-180 derived from
symmetry) and 79 columns (for the maximum number of screen columns). A
single byte in the range 0..49 (represent -24..+24) could hold the data, all
in under 8K. (Ignorning the actual initialization of the array itself!)

Presumably a similar analysis could apply to SQR(LOG(3.14 * Y)). If there
are only 25 possible values of Y, this becomes a trivial lookup operation,
again with the data being generated from another language.


Magnus Olsson

unread,
Nov 2, 2000, 2:12:09 AM11/2/00
to
In article <DMXL5.12281$mC.7...@monger.newsread.com>,

Matthew T. Russotto <russ...@wanda.vf.pond.com> wrote:
>In article <8tpdp9$gql$1...@news.lth.se>, Magnus Olsson <m...@pobox.com> wrote:
>}
>}I suggested using fixed-point maths in an earlier post, but the problem
>}is the (very) limited precision offered by Inform's 16-bit integers.
>}And when the code contains transcendental functions such as sin and log
>}the proting is decidedly non-trivial (taking the square root of a
>}fixed-point number is easy; taking the sine isn't).
>
>Microsoft did floating point, sines, cosines, etc for BASIC in less
>than 12K of 6502 (8-bit, not so much as a hardware multiply)
>assembler;

As did lots of other people at the time. And Digital put entire
time-sharing OS's (OS/8 etc) in 4K of 12-bit words on the PDP-8.

>I hardly think that Inform running on a more powerful
>virtual machine with a larger memory model is going to make it
>impossible.

Did I say it was impossible? I wrote that it is decidedly non-trivial.
(And finding the best algorithms is a non-trivial mathematical problem
as well as a programming one. OK, they're written up in the
literature, but then you have to know where to look, and be good at
reading mathematicla literature.)

It's all quite doable (in fact, I'm tempted to do it myself if I ever
run out of things to do - hah!), but rather a steep threshold to get
over in order to port a few old Basic games, don't you think?

Iain Merrick

unread,
Nov 2, 2000, 6:31:37 AM11/2/00
to
Andrew Plotkin wrote:
[...]

> Does TADS have a floating-point data type?

TADS 2 doesn't, TADS 3 does.

> Does it operate deterministically, or will
> different implementations have different precisions?

The TADS 3 floating-point routines use decimal numbers at a precision
specified by the program. (That is, it doesn't just use doubles and
math.h.) The code is sufficiently scary that writing another
implementation won't be easy, but another _good_ implementation should
give exactly the same results.

--
Iain Merrick
i...@spod-central.org

Richard Bos

unread,
Nov 2, 2000, 7:23:43 AM11/2/00
to
d...@pearl.tao.co.uk (David Given) wrote:

> > "Muffy St. Bernard" wrote:
> >> A$ = B$ + " foo " + MID$(B$, LEN(B$) - 3, 1)
>
> Inform string handling is like C. I'd do something like:
>
> char* foo(char* bstring)
> {
> int len = strlen(bstring);
> char* astring = malloc(len*3); /* maximum length of output */

No, it isn't. What if bstring contains "x"? What if malloc() fails?

> strcpy(astring, bstring);
> strcat(astring, " foo ");
> {
> char* p = astring + strlen(astring);
> *p++ = bstring[len - 3];
> *p = '\0';
> }
> return astring;
> }

What about this:

char *foo(char *bstring)
/* If you decide to use " foo! " instead, you won't have to change
all seventy-and-a-half occurences if you use a #define. */
#define FOOSTRING " foo "
{
size_t len=strlen(bstring);
/* Space for bstring + FOOSTRING + 1 char + null terminator. */
char *astring=malloc(len+strlen(FOOSTRING)+1+1);

if (astring)
sprintf(astring, "%s%s%c", bstring, FOOSTRING, bstring[len-3]);
return astring;
}

*printf are _nice_, once you get to know them reasonably well. *scanf(),
OTOH, are nasty.

Richard

Muffy St. Bernard

unread,
Nov 2, 2000, 8:56:38 AM11/2/00
to
Magnus Olsson wrote:

> It's all quite doable (in fact, I'm tempted to do it myself if I ever
> run out of things to do - hah!), but rather a steep threshold to get
> over in order to port a few old Basic games, don't you think?

Yes. :-)
It would be interesting to implement if implementing it was the
point...but not if the point is just trying to reproduce the output of
your (well, my) favourite old BASIC games.

Muffy.

Jurgen Lerch)

unread,
Nov 3, 2000, 3:00:00 AM11/3/00
to
Saluton!

Muffy St. Bernard <muffy...@hotmail.com> wrote:

What about doing a kind of rational class, in other
words numbers of the form

integer
---------------- ?
positive integer

sqrt, sin, etc. are probably not easier than in pure int,
but it might help with other calculations.

Ad Astra!
JuL

--
ler...@uni-duesseldorf.de ,,Don't do it. Or Try.
Jürgen "JuL" Lerch There is no Do.'' (me)
http://www-public.rz.uni-duesseldorf.de/~lerchj/

David Thornley

unread,
Nov 3, 2000, 11:44:13 PM11/3/00
to
In article <8tuqde$a...@poseidon.rz.uni-duesseldorf.de>,
J"urgen Lerch <ler...@uni-duesseldorf.de> wrote:
>Saluton!

>
>
>What about doing a kind of rational class, in other
>words numbers of the form
>
> integer
> ---------------- ?
> positive integer
>
>sqrt, sin, etc. are probably not easier than in pure int,
>but it might help with other calculations.
>
Rationals like that have a distressing habit of having the numerator
and denominator expand with serious arithmetic. I think I'd rather
use integers to denote hundredths or so. This does require scaling
after every divide or multiply, and risks losing some precision.

And forget about doing the transcendental functions by calculation.
It's not worth it. For the sort of precision that this would require,
lookup tables will do just fine. (This problem was present in some
early robot arms: how do you get a 6502 to do sines and cosines fast?
The software answer was to do a lookup table and a little extra fiddling,
as opposed to the hardware answer which was plugging in a more powerful
CPU with a math coprocessor.)

Sines and cosines: a lookup table for 0-90 degrees (I don't think we
need concern ourselves with radians). Do it with 91 entries, and use
symmetry. Interpolate as necessary. These are rather well-behaved
functions (no nth derivative at any point has an absolute value greater
than 1), so interpolation should work fairly well.

Tangents: sine divided by cosine, checking to make sure cosine is
nonzero.

Log: lookup table for 1-10, at appropriate intervals, and scale.

Powers: integer powers are easy, others will be considerably harder.
Do on an ad hoc basis.

Square roots: this might be worth calculating, being fairly simple.
If nothing else, a lookup table with one application of Newton's
method.

The intent here is not to be fast but to be easy to write. As can
be seen, it still is going to be awkward and clumsy, but for games that
need transcendentals that's going to be true of every method.

--
David H. Thornley | If you want my opinion, ask.
da...@thornley.net | If you don't, flee.
http://www.thornley.net/~thornley/david/ | O-

Magnus Olsson

unread,
Nov 4, 2000, 3:00:00 AM11/4/00
to
In article <xuMM5.6217$FU3.1...@ptah.visi.com>,

David Thornley <thor...@visi.com> wrote:
>In article <8tuqde$a...@poseidon.rz.uni-duesseldorf.de>,
>J"urgen Lerch <ler...@uni-duesseldorf.de> wrote:
>>Saluton!
>>
>>
>>What about doing a kind of rational class, in other
>>words numbers of the form
>>
>> integer
>> ---------------- ?
>> positive integer
>>
>>sqrt, sin, etc. are probably not easier than in pure int,
>>but it might help with other calculations.
>>
>Rationals like that have a distressing habit of having the numerator
>and denominator expand with serious arithmetic.

Indeed. To avoid overflow, we'd have to settle for approximations -
and in that case we could just as well use fixed-point arithmetic
anyway. (Just like fixed-point maths, but unlike floating-point,
rational numbers with limited numerator and denominator have a rather
small range).

Functions like square root and sine would also be a whole lot harder
to implement than in fixed-point arithmetic.

>I think I'd rather
>use integers to denote hundredths or so. This does require scaling
>after every divide or multiply, and risks losing some precision.

This sounds like fixed-point arithmetic.

>And forget about doing the transcendental functions by calculation.
>It's not worth it. For the sort of precision that this would require,
>lookup tables will do just fine. (This problem was present in some
>early robot arms: how do you get a 6502 to do sines and cosines fast?
>The software answer was to do a lookup table and a little extra fiddling,
>as opposed to the hardware answer which was plugging in a more powerful
>CPU with a math coprocessor.)

It depends, of course, on the application, but I think for games such
"artillery" lookup tables would suffice, possibly with some simple
interpolation algorithm.

>Powers: integer powers are easy, others will be considerably harder.
>Do on an ad hoc basis.

Non-integral powers could be done as

x^y = exp(y * log(x))

(as indeed they are implemented in most FP libraries).

>Square roots: this might be worth calculating, being fairly simple.
>If nothing else, a lookup table with one application of Newton's
>method.

There are better algorithms than that; it's similar to long division
and (for binary numbers) it requires only shifts and logical operations.

Jonadab the Unsightly One

unread,
Nov 6, 2000, 3:00:00 AM11/6/00
to
ical...@my-deja.com wrote:

> In article <8tonv9$b33$1...@news.lth.se>,
> m...@pobox.com (Magnus Olsson) wrote:
>
> > Floating-point arithmetic is a trickier case, in terms of difficulty
> > but mostly in terms of demand - I don't think very many adventure
> > games really need floating point.
>
> It would sure make the implementation of money easier. Dangerous
> Curves' money-handling routines were labyrinthine, to say the least.

Money should be fixed point, I would think.

Gas prices notwithstanding. (Anyway, even those never have more
than three places after the decimal.)

--
"Popularity and quality are orthogonal." -- jonadab

0 new messages