New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add floating point math support #179

Merged
merged 41 commits into from Jun 26, 2017

Conversation

Projects
None yet
3 participants
@ajcord
Copy link
Contributor

ajcord commented Jun 26, 2017

Resolves KnightOS/KnightOS#216

It's not finished yet, but I think it's time this started to get reviewed. I stuck to relatively basic operations on floating points and left the rest to userspace. As far as I can tell, besides some non-critical issues with fptostr, the only major issue currently is adding negative numbers. That being said, my testing has not been exhaustive.

Here is what's done:

  • String/integer to FP conversion
  • FP to string conversion
  • Loading common constants
  • Addition of positive numbers
  • Multiplication/division by powers of ten only
  • Logical operators (and, or, xor, not)
  • Negation, absolute value
  • Comparison, min, max
  • Integer and fractional part
  • Random number generation

Here is what's left to do, ranked by how important I think it is:

  1. Adding negative numbers (i.e. subtraction)
  2. Multiplication and division
  3. Roots/powers
  4. Logarithms
  5. Trigonometry
  6. Any other miscellaneous math operations
  7. Conversion to and from IEEE 754 floats/doubles

Hopefully it's up to par in terms of style and efficiency. I'm not super experienced with Z80, so some portions can get a bit ugly (mostly fptostr and fpAdd).

Feel free to let me know about any problems you find, but my availability is going to decrease over the next few weeks. I will no longer be able to contribute in about a month (but should still be able to answer questions about my code). Ideally, someone else will take over to flesh out the rest.

ajcord added some commits Jun 6, 2017

Add integer to FP conversion
Uses an encoding similar to TI-OS but with fewer flags.
Add FP subtract, negate, compare; begin addition
Addition is currently just standard BCD addition on the mantissa. Still
need to work on handling signs, exponents, and overflows.
Fix/optimize various things
Only 1 bug away from addition being able to handle signed operands
Add conversion from string to floating point
I’ve tested several cases I can think of, but it should really get
tested more thoroughly.
Optimize strtofp
Now using a single rld instruction instead of multiple sla
instructions. Also now formally assumes the destination is zeroed,
which it previously only partially did.
Add carry support to fpAdd
fpAdd can now correctly add two positive numbers that have the same
exponent.
Add floating point support for fpAdd
The code is rather ugly, but it appears to work. I’ll try to come back
to this section at some point to clean it up.
Add initial fptostr conversion
Would like to implement display options instead of always using
scientific notation, but this works fine for testing.
Start implementation of various fptostr options
Currently very buggy and ugly.
Fix known bugs in fptostr
Also combines scientific notation processing with normal processing to
share code. Should probably move away from using IX now since it’s slow.
First attempt at rounding in fptostr
Correctly rounds 3.1415926535897 to 3.141592654, but crashes on
variations like 0.1415926535897, 11.1415926535897.
Abandon rounding for now
Too much work for not much gain at this point. Also fixed the crashing
bug.

@ddevault ddevault merged commit b9a5ee2 into KnightOS:master Jun 26, 2017

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jun 26, 2017

Thanks!

FP_180_OVER_PI .equ 6
FP_E .equ 7
FP_LOG_E .equ 8
FP_LN_E .equ 9

This comment has been minimized.

@ajcord

ajcord Jun 26, 2017

Contributor

Should be FP_LN_10

This comment has been minimized.

@ddevault

ddevault Jun 26, 2017

Member

Whoops, fixed

;; * Rounding last digit - buggy, currently abandoned
;; * Never show exponent if significand is 0 - not started
;; Examples:
;; All nonzero decimals in scientific notation, digits grouped with ',':

This comment has been minimized.

@ajcord

ajcord Jun 26, 2017

Contributor

This example doesn't make much sense because scientific notation will never have thousands separators. Might make more sense to change this to FP_STR_INV_PUNC | FP_DISP_SCIENTIFIC | 0xF, and then make the next one FP_GROUP_DIGITS | 5

This comment has been minimized.

@ddevault

ddevault Jun 26, 2017

Member

Good point.

@ddevault

This comment has been minimized.

@ajcord

This comment has been minimized.

Copy link
Contributor

ajcord commented Jun 26, 2017

Looks like some formatting issues with those labeled "Input" or "Output" instead of "Inputs" or "Outputs", and a list indentation issue with itofp, but otherwise looks good 👍

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jun 26, 2017

Yep, one step at a time. Fixing the rest of the build server at the moment <_<

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jun 26, 2017

Project infrastructure isn't generally healthy after 8 months of negligence

@ajcord

This comment has been minimized.

Copy link
Contributor

ajcord commented Jun 26, 2017

Understandable

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jun 26, 2017

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 1, 2017

Hmm, I ran into an issue with fptostr:

  ld a, FP_PI
  kld(hl, .pi)
  pcall(fpLoadConst)
  xor a
  kld(ix, .pi)
  kld(hl, .str)
  pcall(fptostr)
  ; (draw the string)
.pi:
  .block 9
.str:
  .block 20

This displays "3".

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 1, 2017

Also tested parsing "3.1415" and printing that, also displays 3. Seems like the fractional part is never displayed.

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 1, 2017

Derp, I needed to set A to 0xF.

@ajcord

This comment has been minimized.

Copy link
Contributor

ajcord commented Jul 1, 2017

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 1, 2017

Generally speaking we design our APIs so that 0 for flag fields does the most sane thing possible. In this case, however, I could go either way.

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 1, 2017

Progress on the calculator is going well, by the way:

https://github.com/KnightOS/calculator

@ajcord

This comment has been minimized.

Copy link
Contributor

ajcord commented Jul 2, 2017

I would have preferred to design the API like you mentioned where 90% of the time you would use A=0. The best solution I can think of is to use bit 5 to indicate fixed point and the bottom nibble for the number of digits, but I don't like that because it wastes the last available flag bit unnecessarily.

Also, great work on the calculator app! I'll be excited to actually be able to do math on my calculator again.

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 3, 2017

Been looking into subtraction. It seems we'll want to do the 9's compliment again at the end, but I'm having a hard time getting everything to work.

@ajcord

This comment has been minimized.

Copy link
Contributor

ajcord commented Jul 3, 2017

@Zeda

This comment has been minimized.

Copy link
Contributor

Zeda commented Jul 3, 2017

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 3, 2017

Thanks @Zeda - BCD is in use here, but the current approach is to use the 9's compliment and only implement addition. It might be easier to do subtraction separately but I'm not particular either way.

Thanks for the tips, I would definitely welcome your eyeballs on this code if you find some spare time.

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 8, 2017

@ajcord can I interest you in writing a blog post for knightos.org about your work?

@ajcord

This comment has been minimized.

Copy link
Contributor

ajcord commented Jul 8, 2017

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Jul 8, 2017

Sure! Send a pull request to https://github.com/KnightOS/knightos.org whenever you like.

@ajcord

This comment has been minimized.

Copy link
Contributor

ajcord commented Aug 7, 2017

I talked to some great Z80 developers at the Vintage Computer Festival today, and one of them suggested implementing x*y as 10^(log(x) + log(y)). Might be worth looking into, although I suspect it may lose some precision and be less efficient. But it could still be worthwhile as a proof of concept once logarithms and powers are implemented.

@Zeda

This comment has been minimized.

Copy link
Contributor

Zeda commented Aug 7, 2017

@ddevault

This comment has been minimized.

Copy link
Member

ddevault commented Aug 7, 2017

Do you need 94 bytes of scrap RAM or 94 bytes of statically allocated LUTs? Both are easily doable, fwiw.

@Zeda

This comment has been minimized.

Copy link
Contributor

Zeda commented Aug 7, 2017

@Zeda

This comment has been minimized.

Copy link
Contributor

Zeda commented Aug 8, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment