Compare commits
52 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a8ada6b7d6 | ||
|
33cd262674 | ||
|
9770525dba | ||
|
c6901dc442 | ||
|
5bc3b881a1 | ||
|
086f814e7b | ||
|
25db3835e0 | ||
|
78cb37bf54 | ||
|
2a301e71a9 | ||
|
380b90d434 | ||
|
774be02e1f | ||
|
5bcfb8a371 | ||
|
1e6d786482 | ||
|
c6ac1e5e2c | ||
|
f15790f252 | ||
|
81253d8934 | ||
|
540d9e282c | ||
|
d3cddc1326 | ||
|
714cd69b9c | ||
|
46851eab9f | ||
|
08f1d199c1 | ||
|
89f442cae8 | ||
|
18692d9baf | ||
|
0a552c9f61 | ||
|
bc8c3aab8e | ||
|
bef903b20a | ||
|
233f347ecc | ||
|
10ec4efed3 | ||
|
a5e64e89d4 | ||
|
273e2f5742 | ||
|
5f6a375c06 | ||
|
b43f0b9480 | ||
|
64754395be | ||
|
d8d7f98663 | ||
|
2b915a3e59 | ||
|
5f0bd3886a | ||
|
2903579efd | ||
|
b56523fadf | ||
|
370df33a6c | ||
|
9deae8128d | ||
|
0b5e011017 | ||
|
e4ad37623b | ||
|
3e5648de87 | ||
|
2caedc9a45 | ||
|
f95aa9ab82 | ||
|
13d26e7b75 | ||
|
28243c267d | ||
|
a491ab0461 | ||
|
2a9801e676 | ||
|
4316f928f8 | ||
|
7593260487 | ||
|
3f7dfe460b |
1
.github/actions/stc_docker/Dockerfile
vendored
Symbolic link
1
.github/actions/stc_docker/Dockerfile
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Dockerfile
|
1
.github/actions/stc_docker/action.yml
vendored
Symbolic link
1
.github/actions/stc_docker/action.yml
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
../../../action.yml
|
31
.github/workflows/main.yml
vendored
Normal file
31
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
stc_rpncalc_ci_job:
|
||||
runs-on: ubuntu-latest
|
||||
name: Test building
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Docker layer cache
|
||||
uses: satackey/action-docker-layer-caching@v0.0.8
|
||||
- name: Docker
|
||||
run: $GITHUB_WORKSPACE/steps/compose_build.sh
|
||||
- name: Desktop build/check
|
||||
run: $GITHUB_WORKSPACE/steps/compose_run.sh desktop_build_check.sh --rebuild
|
||||
- name: Calc build
|
||||
run: $GITHUB_WORKSPACE/steps/compose_run.sh build_calc.sh
|
||||
- name: ls
|
||||
run: ls $GITHUB_WORKSPACE
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: stc_rpncalc_artifacts
|
||||
path: |
|
||||
${{ github.workspace }}/build/
|
||||
${{ github.workspace }}/build_qt/lcov/
|
||||
${{ github.workspace }}/build_qt/decn.c.gcov
|
||||
${{ github.workspace }}/build_qt/Testing/
|
||||
${{ github.workspace }}/main.hex
|
||||
if-no-files-found: error
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
*.swp
|
||||
*.hex
|
||||
*.bak
|
||||
CMakeLists.txt.user
|
||||
|
@ -3,15 +3,24 @@ project(stc_rpncalc C CXX)
|
||||
# 3rd party tools
|
||||
find_package(Qt5 COMPONENTS Widgets Qml Quick REQUIRED)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
message(STATUS "using address sanitizer")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls")
|
||||
link_libraries(asan)
|
||||
endif()
|
||||
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type (for tests debug make sense)")
|
||||
|
||||
# Compiler warnings
|
||||
if(MSVC)
|
||||
add_compile_options(/W4 /WX)
|
||||
add_compile_options(/W4 /WX)
|
||||
else()
|
||||
add_compile_options(-Wall -Wextra -pedantic)
|
||||
add_compile_options(-Wall -Wextra -pedantic)
|
||||
endif()
|
||||
|
||||
# CTest Catch2 tests
|
||||
enable_testing()
|
||||
|
||||
# Directory with source code
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(qt_gui)
|
||||
|
21
Dockerfile
Normal file
21
Dockerfile
Normal file
@ -0,0 +1,21 @@
|
||||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||
build-essential \
|
||||
clang \
|
||||
cmake \
|
||||
git \
|
||||
lcov \
|
||||
libboost-dev \
|
||||
libgmp-dev \
|
||||
libmpfr-dev \
|
||||
ninja-build \
|
||||
qtdeclarative5-dev \
|
||||
sdcc=3.5.0+dfsg-2build1 \
|
||||
vim-tiny \
|
||||
wget
|
||||
|
||||
# install more up-to-date catch2
|
||||
RUN wget http://mirrors.kernel.org/ubuntu/pool/universe/c/catch2/catch2_2.13.7-1_amd64.deb
|
||||
RUN echo "3ca43a3b3347ec2e220e0cc6e9c38859 catch2_2.13.7-1_amd64.deb" | md5sum --check --
|
||||
RUN dpkg -i catch2_2.13.7-1_amd64.deb
|
7
Makefile
7
Makefile
@ -1,11 +1,12 @@
|
||||
SDCC ?= sdcc
|
||||
STCCODESIZE ?= 13312
|
||||
SDCCOPTS ?= --code-size $(STCCODESIZE) --xram-size 256 --idata-loc 0x80
|
||||
SDCCOPTS ?= --code-size $(STCCODESIZE) --xram-size 256 --idata-loc 0x70
|
||||
#SDCCOPTS ?= --code-size $(STCCODESIZE) --xram-size 256 --stack-auto --model-large
|
||||
FLASHFILE ?= main.hex
|
||||
LARGE_LDFLAGS += -L/usr/share/sdcc/lib/large/
|
||||
# CFLAGS += -DSTACK_DEBUG # write the stack pointer to P3_4
|
||||
|
||||
SRC = src/lcd.c src/key.c src/utils.c src/decn/decn.c src/calc.c
|
||||
SRC = src/lcd.c src/key.c src/utils.c src/decn/decn.c src/calc.c src/stack_debug.c
|
||||
|
||||
OBJ=$(patsubst src%.c,build%.rel, $(SRC))
|
||||
|
||||
@ -13,7 +14,7 @@ all: main
|
||||
|
||||
build/%.rel: src/%.c src/%.h
|
||||
mkdir -p $(dir $@)
|
||||
$(SDCC) $(SDCCOPTS) -o $@ -c $<
|
||||
$(SDCC) $(SDCCOPTS) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
main: $(OBJ)
|
||||
$(SDCC) -o build/ src/$@.c $(SDCCOPTS) $(CFLAGS) $^
|
||||
|
285
README.md
285
README.md
@ -1,10 +1,30 @@
|
||||
# STC DIY Calculator Firmware
|
||||
|
||||
This is a replacement firmware for the [diyleyuan calculator kit](http://www.diyleyuan.com/jc/L8Q.html). The calculator kit is available for purchase for less than $13 shipped from eBay by searching for "diy calculator kit". You will have to solder the kit yourself (see "hardware connections" below). The calculator uses an STC IAP15W413AS microcontroller (an 8051 instruction set-compatible microcontroller) with a built-in serial-port bootloader. See the series [summary](http://www.stcmicro.com/datasheet/STC15W408AS_Features.pdf) and full english [datasheet](https://www.stcmicro.com/datasheet/STC15F2K60S2-en.pdf). This project uses [SDCC](http://sdcc.sourceforge.net/) to compile the C code and [stcgal](https://github.com/grigorig/stcgal) to load the new firmware.
|
||||
This is a replacement firmware for the [diyleyuan calculator kit](http://www.diyleyuan.com/jc/L8Q.html).
|
||||
The calculator kit is available for purchase for less than $13 shipped from eBay by searching for "diy calculator kit"
|
||||
(price has increased recently, currently closer to $18 shipped).
|
||||
You will have to solder the kit yourself (see "hardware connections" below).
|
||||
The calculator uses an STC IAP15W413AS microcontroller
|
||||
(an 8051 instruction set-compatible microcontroller)
|
||||
with a built-in serial-port bootloader.
|
||||
See the series [summary](http://www.stcmicro.com/datasheet/STC15W408AS_Features.pdf)
|
||||
and full english [datasheet](https://www.stcmicro.com/datasheet/STC15F2K60S2-en.pdf).
|
||||
This project uses [SDCC](http://sdcc.sourceforge.net/) to compile the C code
|
||||
and [stcgal](https://github.com/grigorig/stcgal) to load the new firmware.
|
||||
|
||||
The replacement firmware supports floating-point calculations (using 18 decimal digits plus exponent for arithmetic) with a 4-level RPN stack. Functions include basic arithmetic as well as log(), exp(), y^x, 1/x and sqrt(), all in floating point. (The original firmware supported only fixed-point calculations in chain mode.) I have not added in the resistor value calculator or the decimal/hexadecimal converter features from the original firmware.
|
||||
The replacement firmware supports floating-point calculations
|
||||
(using 18 decimal digits plus exponent for arithmetic)
|
||||
with a 4-level RPN stack.
|
||||
Functions include basic arithmetic as well as log(), exp(), y^x, 1/x and sqrt(),
|
||||
all in floating point.
|
||||
(The original firmware supported only fixed-point calculations in chain mode.)
|
||||
I have not added in the resistor value calculator or the decimal/hexadecimal converter features from the original firmware.
|
||||
|
||||
Note that once you change the firmware on the calculator, there's no way to go back to the original firmware (the original firmware isn't posted for download anywhere). STC's bootloader on the microcontroller deliberately prevents readback of the microcontroller's content, and STC considers this to be a "feature".
|
||||
Note that once you change the firmware on the calculator,
|
||||
there's no way to go back to the original firmware
|
||||
(the original firmware isn't posted for download anywhere).
|
||||
STC's bootloader on the microcontroller deliberately prevents readback of the microcontroller's content,
|
||||
and STC considers this to be a "feature".
|
||||
|
||||
Here's a picture of the assembled calculator kit running the new firmware:
|
||||
|
||||
@ -28,9 +48,15 @@ The calculator uses RPN. Calculate (2+3)/(9^2) by pressing the following keys:
|
||||
- `*`
|
||||
- `÷`
|
||||
|
||||
The = key is used for Enter. There is automatic stack lift so that `9`, `Enter`, `*` is equivalent to 9^2. The stack is a classic 4-level RPN stack, where the T register automatically duplicates.
|
||||
The = key is used for Enter.
|
||||
There is automatic stack lift so that
|
||||
`9`, `Enter`, `*`
|
||||
is equivalent to 9^2.
|
||||
The stack is a classic 4-level RPN stack,
|
||||
where the T register automatically duplicates.
|
||||
|
||||
The decimal key also doubles as the enter exponent key. For example the following calculates 3E8 / 1550E-9:
|
||||
The decimal key also doubles as the enter exponent key.
|
||||
For example the following calculates 3E8 / 1550E-9:
|
||||
|
||||
- 3
|
||||
- .
|
||||
@ -52,7 +78,11 @@ The decimal key also doubles as the enter exponent key. For example the followin
|
||||
- 9
|
||||
- `÷`
|
||||
|
||||
There is currently no way to force the calculator to display in scientific mode. For extremely large numbers that are hard to read, taking the log base 10 of a number will give its exponent. Numbers larger than 18 digits will automatically be displayed in scientific notation, as will numbers smaller than 1E-3.
|
||||
There is currently no way to force the calculator to display in scientific mode.
|
||||
For extremely large numbers that are hard to read,
|
||||
taking the log base 10 of a number will give its exponent.
|
||||
Numbers larger than 18 digits will automatically be displayed in scientific notation,
|
||||
as will numbers smaller than 1E-3.
|
||||
|
||||
## Keys
|
||||
Some of the keys have slightly different functions, see the picture of the emulator Qt GUI.
|
||||
@ -74,31 +104,62 @@ The keys on the *original* calculator map as follows:
|
||||
- The 2nd press begins exponent entry.
|
||||
- The 3rd and subsequent presses negates the current exponent being entered.
|
||||
- Acts as STO when shifted (there is only 1 memory register)
|
||||
- `mode `: acts as a shift key
|
||||
- `mode `: acts as a shift key (press multiple times to toggle between shift up, shift down, and no shift)
|
||||
- `ON/AC`: acts as a backspace key during digit entry, acts as `Clear X` when digit entry is finished (e.g. after an operator key is pressed)
|
||||
- acts as `Clear X` when shifted
|
||||
- `7 `: acts as y^x when shifted
|
||||
- `8 `: acts as ln(x) when shifted
|
||||
- `9 `: acts as log(x) when shifted
|
||||
- `÷ `: acts as pi when shifted
|
||||
- `4 `: acts as roll down when shifted
|
||||
- acts as roll up when shifted down
|
||||
- `5 `: acts as e^x when shifted
|
||||
- `6 `: acts as 10^x when shifted
|
||||
- `4 `: acts as roll down when shifted
|
||||
- `1 `: acts as sin(x) when shifted
|
||||
- acts as asin(x) when shifted down
|
||||
- `2 `: acts as cos(x) when shifted
|
||||
- acts as acos(x) when shifted down
|
||||
- `3 `: acts as tan(x) when shifted
|
||||
- acts as atan(x) when shifted down
|
||||
- all trig functions are calculated in degrees
|
||||
- `- `: acts as to degrees when shifted
|
||||
- acts as to radians when shifted down
|
||||
- `+ `: acts as LastX when shifted
|
||||
- `0 `: acts as off button when shifted
|
||||
|
||||
|
||||
## Floating Point
|
||||
|
||||
The calculator internally calculates with an 18 digit significand for better precision, even though at most 16 digits can be displayed. The exponent display is fixed at 2 digits (when it is displayed), but the calculator doesn't prevent you from doing certain operations (e.g. basic arithmetic) which result in numbers with larger exponents.
|
||||
The calculator internally calculates with an 18 digit significand for better precision,
|
||||
even though at most 16 digits can be displayed.
|
||||
The exponent display is fixed at 2 digits (when it is displayed),
|
||||
but the calculator doesn't prevent you from doing certain operations
|
||||
(e.g. basic arithmetic) which result in numbers with larger exponents.
|
||||
|
||||
Internally, the calculator dedicates 15 bits for representing the signed exponent, so exponents up to +/- 16,383 can be represented (see the internals section below for more information). This is to ensure that intermediate parts of certain calculations (mainly taking the reciprocal of a number) do not prematurely cause overflow or underflow, even when the result is fully representable with just 2 digits. You can do calculations with greater than 2 digits in the exponent, but only 2 digits will be displayed. For larger exponents, a 10 in the ten's place of the exponent will be displayed as a '`:`'. (This just so happens to be the next character after '`9`' in the 1602 LCD's character map).
|
||||
Internally, the calculator dedicates 15 bits for representing the signed exponent,
|
||||
so exponents up to +/- 16,383 can be represented
|
||||
(see the internals section below for more information).
|
||||
This is to ensure that intermediate parts of certain calculations
|
||||
(mainly taking the reciprocal of a number)
|
||||
do not prematurely cause overflow or underflow,
|
||||
even when the result is fully representable with just 2 digits.
|
||||
You can do calculations with greater than 2 digits in the exponent,
|
||||
but only 2 digits will be displayed.
|
||||
For larger exponents,
|
||||
a 10 in the ten's place of the exponent will be displayed as a '`:`'.
|
||||
(This just so happens to be the next character after '`9`' in the 1602 LCD's character map).
|
||||
|
||||
## Turning off
|
||||
Press `Shift` (the `mode` key on the physical calculator) and then `0` to turn off. On older stc_rpncalc firmwares, or if the calculator is unresponsive, hold `Shift` (the `mode` key on the physical calculator) and `0` *at the same time* to turn off. NOTE: There is no auto power off.
|
||||
Press `Shift` (the `mode` key on the physical calculator) and then `0` to turn off.
|
||||
On older stc_rpncalc firmwares,
|
||||
or if the calculator is unresponsive,
|
||||
hold `Shift` (the `mode` key on the physical calculator) and `0` *at the same time* to turn off.
|
||||
NOTE: There is no auto power off.
|
||||
|
||||
|
||||
# Building
|
||||
There is a prebuilt binary for the calculator checked in at `binaries/main.hex` for the calculator. Building is fairly straigtforward though.
|
||||
Github releases has prebuilt binaries for the calculator.
|
||||
Building is fairly straigtforward though.
|
||||
|
||||
- Use the Makefile for building a new firmware for the calculator.
|
||||
- type `make` to build
|
||||
@ -108,14 +169,25 @@ There is a prebuilt binary for the calculator checked in at `binaries/main.hex`
|
||||
- See https://sourceforge.net/p/sdcc/discussion/1865/thread/9589cc8d57/
|
||||
- Luckily SDCC has few dependencies, and older versions can be installed fairly easily.
|
||||
- CMakeLists.txt is for building the Qt desktop application, and also the decimal-number-library test application.
|
||||
- build similarly to other cmake projects:
|
||||
- build similarly to other cmake projects, see [Dockerfile](Dockerfile) for build dependencies:
|
||||
- `mkdir build_qt && cd build_qt`
|
||||
- `cmake -DCMAKE_BUILD_TYPE=Debug -G "Eclipse CDT4 - Ninja" ..`
|
||||
- (you can choose a different generator, I prefer using Ninja to build, because it's fast)
|
||||
- `ninja`
|
||||
|
||||
# Installing
|
||||
Note that once you change the firmware on the calculator, it isn't possible to go back to the original firmware. The STC microcontroller used has a bootloader permanently stored in ROM that allows downloading new firmware over a serial port (but not reading the existing firmware). You can re-program it using a USB-to-logic-level-serial (5V) dongle, and the stcgal program. WARNING: a lot of USB-to-logic-level-serial dongles are for 3.3V logic levels instead of the 5V needed. Also note that this is a "logic-level" serial port, and not RS232 levels, which are generally a high negative voltage. The diyleyuan calculator runs at 5V to make it easier to power/drive the LCD display. You have a couple of options:
|
||||
Note that once you change the firmware on the calculator,
|
||||
it isn't possible to go back to the original firmware.
|
||||
The STC microcontroller used has a bootloader permanently stored in ROM that allows downloading new firmware over a serial port
|
||||
(but not reading the existing firmware).
|
||||
You can re-program it using a USB-to-logic-level-serial (5V) dongle,
|
||||
and the stcgal program.
|
||||
WARNING: a lot of USB-to-logic-level-serial dongles are for 3.3V logic levels instead of the 5V needed.
|
||||
Also note that this is a "logic-level" serial port,
|
||||
and not RS232 levels,
|
||||
which are generally a high negative voltage.
|
||||
The diyleyuan calculator runs at 5V to make it easier to power/drive the LCD display.
|
||||
You have a couple of options:
|
||||
|
||||
1. Buy a USB to logic-level serial dongle that supports 5V operation (these dongles may have a jumper you need to set to switch between 3.3V and 5V). This is the best option.
|
||||
- Here is one that works: https://www.amazon.com/gp/product/B00N4MCS1A/
|
||||
@ -134,11 +206,20 @@ Note that once you change the firmware on the calculator, it isn't possible to g
|
||||
Connect to Tx of the USB dongle.
|
||||
- Pin 16 is Tx from the microcontroller (purple wire in the picture). Connect to Rx of the USB dongle.
|
||||
|
||||
I recommend soldering Tx and Rx wires into the plated through holes on the PCB while soldering up the kit, so that the connections are more permanent. I soldered the wires from the back side (leave space for the screw hole). Note that you must "cross over" Tx/Rx going between the microcontroller and the USB dongle (i.e. Rx on the microcontroller goes to Tx on the USB dongle, and Tx on the microcontroller goes to Rx on the USB dongle).
|
||||
I recommend soldering Tx and Rx wires into the plated through holes on the PCB while soldering up the kit,
|
||||
so that the connections are more permanent.
|
||||
I soldered the wires from the back side (leave space for the screw hole).
|
||||
Note that you must "cross over" Tx/Rx going between the microcontroller and the USB dongle
|
||||
(i.e. Rx on the microcontroller goes to Tx on the USB dongle,
|
||||
and Tx on the microcontroller goes to Rx on the USB dongle).
|
||||
|
||||

|
||||
|
||||
You must also connect ground to the dongle. A good point to use is header P1. (You may optionally power the calculator with +5V from the USB dongle instead of using button-cell batteries. Header P1 is again a good location to use.) To program the calculator see the "Programming with stcgal" section below.
|
||||
You must also connect ground to the dongle.
|
||||
A good point to use is header P1.
|
||||
(You may optionally power the calculator with +5V from the USB dongle instead of using button-cell batteries.
|
||||
Header P1 is again a good location to use.)
|
||||
To program the calculator see the "Programming with stcgal" section below.
|
||||
|
||||
Pin on calculator | Color used | Pin on usb-to-serial dongle
|
||||
------------------|------------|-----------------------------
|
||||
@ -151,27 +232,55 @@ P1 pin 2 (Gnd) | Black | (Gnd)
|
||||
|
||||
#### Voltage regulator
|
||||
|
||||
Be careful when working on the calculator. The 7550 voltage regulator used has no short circuit protection. It does have a low quiescent current and extremely low dropout voltage though, and you must match the low dropout voltage if replacing the regulator. If you do end up damaging the regulator (like I did), a good replacement is the Microchip MCP1700-5002E/TO. (In the picture though, I just removed the 7550 voltage regulator, shorted pins 2 and 3, and added a capacitor between pin 1 and pins 2/3. I am powering the calculator externally, instead of with batteries.)
|
||||
Be careful when working on the calculator.
|
||||
The 7550 voltage regulator used has no short circuit protection.
|
||||
It does have a low quiescent current and extremely low dropout voltage though,
|
||||
and you must match the low dropout voltage if replacing the regulator.
|
||||
If you do end up damaging the regulator (like I did),
|
||||
a good replacement is the Microchip MCP1700-5002E/TO.
|
||||
(In the picture though, I just removed the 7550 voltage regulator, shorted pins 2 and 3,
|
||||
and added a capacitor between pin 1 and pins 2/3.
|
||||
I am powering the calculator externally, instead of with batteries.)
|
||||
|
||||
#### Parasitic powering through the usb-to-serial adapter
|
||||
|
||||
If you have the usb-to-serial adapter connected, the calculator may draw power parasitically through pin 15 (Rx) of the microcontroller. This may prevent the calculator and microcontroller from fully turning off. This may prevent the bootloader from running (which would prevent you from reprogramming the calculator), since the bootloader only runs on power on. To prevent this, use a diode on pin 15 (see image above, or consult the microcontroller datasheet). You may also optionally add a 330 ohm resistor on pin 16 (Tx) of the microcontroller to provide isolation on that pin. (I don't think it's necessary to prevent parasitic power though.)
|
||||
If you have the usb-to-serial adapter connected,
|
||||
the calculator may draw power parasitically through pin 15 (Rx) of the microcontroller.
|
||||
This may prevent the calculator and microcontroller from fully turning off.
|
||||
This may prevent the bootloader from running
|
||||
(which would prevent you from reprogramming the calculator),
|
||||
since the bootloader only runs on power on.
|
||||
To prevent this, use a diode on pin 15
|
||||
(see image above, or consult the microcontroller datasheet).
|
||||
You may also optionally add a 330 ohm resistor on pin 16 (Tx)
|
||||
of the microcontroller to provide isolation on that pin.
|
||||
(I don't think it's necessary to prevent parasitic power though.)
|
||||
|
||||
#### Adding programming connections after the fact
|
||||
|
||||
If you have already soldered the kit together without adding the Tx/Rx serial wires, you can still solder wires directly to the microcontroller fairly easily.
|
||||
If you have already soldered the kit together without adding the Tx/Rx serial wires,
|
||||
you can still solder wires directly to the microcontroller fairly easily.
|
||||
|
||||

|
||||
|
||||
#### Schematic
|
||||
|
||||
Here is the schematic from the diyleyuan website. Note that the schematic symbol for the microcontroller mistakenly labels P5.4 as P0.0, and mistakenly labels P5.5 as P0.1. The net name labels are correct.
|
||||
Here is the schematic from the diyleyuan website.
|
||||
Note that the schematic symbol for the microcontroller mistakenly labels P5.4 as P0.0,
|
||||
and mistakenly labels P5.5 as P0.1.
|
||||
The net name labels are correct.
|
||||
|
||||

|
||||
|
||||
#### Soft-latching power switch
|
||||
|
||||
The soft-latching power switch works as follows: Initially the calculator is off. Both Q1 and Q2 are off. Pressing the On key (S4) turns on Q1 through R1 and D2. Q1 then supplies 5V to the system. Once the microcontroller has power and starts running, it turns on Q2, which keeps Q1 on through R1. To turn off, the microcontroller turns off Q2, which in turn will turn off Q1.
|
||||
The soft-latching power switch works as follows:
|
||||
Initially the calculator is off. Both Q1 and Q2 are off.
|
||||
Pressing the On key (S4) turns on Q1 through R1 and D2.
|
||||
Q1 then supplies 5V to the system.
|
||||
Once the microcontroller has power and starts running,
|
||||
it turns on Q2, which keeps Q1 on through R1.
|
||||
To turn off, the microcontroller turns off Q2, which in turn will turn off Q1.
|
||||
|
||||
#### Component layout
|
||||
|
||||
@ -181,21 +290,47 @@ Here is the component layout from the diyleyuan website.
|
||||
|
||||
#### Keyswitches, LCD, and other recommended replacement components
|
||||
|
||||
The switches used are a knockoff of the Omron B3F series. A good replacement is the B3F-5050 which requires only 130 grams force to depress. The switches included with the kit take more force to depress. (This is somewhat a matter of personal preference though.) I recommend using four 11mm M2 standoffs along with eight M2 screws instead of using the four long screws and nuts provided to hold the top and bottom together. The problem with using the long screws is that in order to tighten them tight enough that they don't become loose easily, the top plate deforms slightly and might interfere with the keys.
|
||||
The switches used are a knockoff of the Omron B3F series.
|
||||
A good replacement is the B3F-5050 which requires only 130 grams force to depress.
|
||||
The switches included with the kit take more force to depress.
|
||||
(This is somewhat a matter of personal preference though.)
|
||||
I recommend using four 11mm M2 standoffs along with eight M2 screws instead of using the four long screws and nuts provided to hold the top and bottom together.
|
||||
The problem with using the long screws is that in order to tighten them tight enough that they don't become loose easily,
|
||||
the top plate deforms slightly and might interfere with the keys.
|
||||
|
||||
User toml_12953 has made a new keyboard template here (todo: can check into git directly?): https://www.dropbox.com/s/7xkg98ywonp4p1l/New%20DIY%20Template.jpg?dl=1
|
||||
User toml_12953 has made a new keyboard template here (todo: can check into git directly?):
|
||||
https://www.dropbox.com/s/7xkg98ywonp4p1l/New%20DIY%20Template.jpg?dl=1
|
||||
|
||||
The LCD used is a fairly standard LCD based on a HD44780-compatible controller. The hole spacing for the screw holes on the LCD is 31mm x 75mm. There are many replacements available, including ones that don't need the backlight on to be readable. I recommend a positive transflective or reflective FSTN type, although the one included (transmissive) is very usable with the backlight on. Here is a picture of a positive FSTN display with the backlight off (shown under strong office lighting):
|
||||
The LCD used is a fairly standard LCD based on a HD44780-compatible controller.
|
||||
The hole spacing for the screw holes on the LCD is 31mm x 75mm.
|
||||
There are many replacements available,
|
||||
including ones that don't need the backlight on to be readable.
|
||||
I recommend a positive transflective or reflective FSTN type,
|
||||
although the one included (transmissive) is very usable with the backlight on.
|
||||
Here is a picture of a positive FSTN display with the backlight off
|
||||
(shown under strong office lighting):
|
||||
|
||||

|
||||
|
||||
The included LCD is a transmissive type, and requires the backlight on to be readable.
|
||||
The included LCD is a transmissive type,
|
||||
and requires the backlight on to be readable.
|
||||
|
||||
I sometimes use an STC15F2K60S2 for development work. This microcontroller is available in a pin-compatible DIP-28 package for less than $2 a piece in single-digit quantities, and has almost 5 times the flash (a downside is that when programming, the flash takes longer to erase). To program a blank microcontroller, you will have to add the following additional options to `stcgal`: `-l 1200 -t 12000`
|
||||
I sometimes use an STC15F2K60S2 for development work.
|
||||
This microcontroller is available in a pin-compatible DIP-28 package for less than $2 a piece in single-digit quantities,
|
||||
and has almost 5 times the flash
|
||||
(a downside is that when programming, the flash takes longer to erase).
|
||||
To program a blank microcontroller,
|
||||
you will have to add the following additional options to `stcgal`: `-l 1200 -t 12000`
|
||||
|
||||
## Programming with stcgal
|
||||
|
||||
Run `stcgal` as shown below, replacing `stc_rpncalc/main.hex` with the actual path to the main.hex you built. There are also prebuilt binaries in the `binaries` directory. In this example, I'm programming at a relatively high line rate of 230,400 bits/s. This works very reliably, but you may want to try at a slower speed to start (omit the `-b 230400` option).
|
||||
Run `stcgal` as shown below,
|
||||
replacing `stc_rpncalc/main.hex` with the actual path to the main.hex you built.
|
||||
There are also prebuilt binaries in the Releases section of github.
|
||||
In this example, I'm programming at a relatively high line rate of 230,400 bits/s.
|
||||
This works very reliably, but you may want to try at a slower speed to start
|
||||
(omit the `-b 230400` option),
|
||||
especially when using an inline resistor and diode.
|
||||
|
||||
~~~~
|
||||
$ ./stcgal.py -P stc15 -b 230400 stc_rpncalc/main.hex
|
||||
@ -239,16 +374,43 @@ Disconnected!
|
||||
(The name for `stcgal` is probably a play on words from the `avrdude` programming software used to program AVR microcontrollers.)
|
||||
|
||||
# Bugs
|
||||
1. After division by 0, ln(-), over/underflow, or other operations which give an `Error`, it's possible to still do certain operations on `Error`. Many functions do check, and will not operate on `Error`, but not all of them yet. This is somewhat similar to old soviet Elektronika calculators where `Error` is just a number, and there wasn't enough ROM space to check for errors. (There are people who explore the inner-workings of these calculators by manipulating the `Error` "number".)
|
||||
1. After division by 0, ln(-), over/underflow, or other operations which give an `Error`,
|
||||
it's possible to still do certain operations on `Error`.
|
||||
Many functions do check, and will not operate on `Error`,
|
||||
but not all of them yet.
|
||||
This is somewhat similar to old soviet Elektronika calculators where `Error` is just a number,
|
||||
and there wasn't enough ROM space to check for errors.
|
||||
(There are people who explore the inner-workings of these calculators by manipulating the `Error` "number".)
|
||||
1. When shifted, keys which do not have a shifted function will instead be interpreted as if there were no shift.
|
||||
1. Trigonometric functions are extremely slow and inaccurate.
|
||||
1. There are probably more bugs waiting to be discovered.
|
||||
|
||||
# Internals
|
||||
## Number Format
|
||||
The original firmware that came with this calculator used a fixed-point format, which significantly limited the range of numbers usable. Additionally, the implementation doesn't actually have enough digits for all displayable results, which can cause errors (e.g. `3,162.277*3,162.28` gives `10,000,010` instead of the correct `10,000,005.31156`).
|
||||
The original firmware that came with this calculator used a fixed-point format,
|
||||
which significantly limited the range of numbers usable.
|
||||
Additionally, the implementation doesn't actually have enough digits for all displayable results,
|
||||
which can cause errors
|
||||
(e.g. `3,162.277*3,162.28` gives `10,000,010` instead of the correct `10,000,005.31156`).
|
||||
|
||||
This replacement calculator firmware uses decimal floating point, using base-100 to store numbers and do calculations. Base-100 allows for efficient storage into 8-bit bytes, and is easier to work with than packed-BCD. Unlike straight binary representations, base-100 is still fairly easy to display as decimal. Also unlike binary representations, there is no conversion error from binary/decimal (e.g. numbers like `0.1` can be represented exactly).
|
||||
This replacement calculator firmware uses decimal floating point,
|
||||
using base-100 to store numbers and do calculations.
|
||||
Base-100 allows for efficient storage into 8-bit bytes,
|
||||
and is easier to work with than packed-BCD.
|
||||
Unlike straight binary representations,
|
||||
base-100 is still fairly easy to display as decimal.
|
||||
Also unlike binary representations, there is no conversion error from binary/decimal
|
||||
(e.g. numbers like `0.1` can be represented exactly).
|
||||
|
||||
Each `uint8_t` stores a base-100 "`digit100`", referred to as an "`lsu`", for least significant unit. (The LSU terminology is borrowed from the decNumber library: I originally considered using the decNumber library similar to the WP-34S calculator, but just the library itself takes several times more flash than is available on this calculator. I also considered using the BigNu mber arduino library, but that library uses C++ and lots of pointers passed to functions, which are extremely expensive on the 8051 architecture.) The number format is as follows:
|
||||
Each `uint8_t` stores a base-100 "`digit100`",
|
||||
referred to as an "`lsu`", for least significant unit.
|
||||
(The LSU terminology is borrowed from the decNumber library:
|
||||
I originally considered using the decNumber library similar to the WP-34S calculator,
|
||||
but just the library itself takes several times more flash than is available on this calculator.
|
||||
I also considered using the BigNumber arduino library,
|
||||
but that library uses C++ and lots of pointers passed to functions,
|
||||
which are extremely expensive on the 8051 architecture.)
|
||||
The number format is as follows:
|
||||
|
||||
- `lsu[0]`: contains the most significant `digit100` (the most significant 2 decimal digits)
|
||||
- implicit decimal point between `lsu[0]/10` and `lsu[0]%10`
|
||||
@ -262,16 +424,23 @@ Each `uint8_t` stores a base-100 "`digit100`", referred to as an "`lsu`", for le
|
||||
- range of exponents only needs to be `+/-99`
|
||||
- using 15 bits for the exponent (instead of e.g. 7 bits) prevents certain intermediate results from prematurely causing overflow
|
||||
|
||||
For example, the number `13.5` is stored normalized (with no leading zeros in the representation) as follows:
|
||||
For example, the number `13.5` is stored normalized
|
||||
(with no leading zeros in the representation) as follows:
|
||||
|
||||
- `lsu[0]`: 13
|
||||
- `lsu[1]`: 50
|
||||
- `lsu[2]` to `lsu[n-1]`: all 0
|
||||
- exponent: 1
|
||||
|
||||
There is an implicit decimal point between the 1 and 3 in `lsu[0]`, so the number is 1.350 * 10^1, which is equivalent to `13.5`. Similarly, the number `1.35` would be stored the exact same way, except now the exponent is 0.
|
||||
There is an implicit decimal point between the 1 and 3 in `lsu[0]`,
|
||||
so the number is 1.350 * 10^1, which is equivalent to `13.5`.
|
||||
Similarly, the number `1.35` would be stored the exact same way, except now the exponent is 0.
|
||||
|
||||
The number `0.135` would be stored the same way, except now the exponent is `0x7FFF` (note that the sign bit is 0, and the bottom 15 bits are the 2's complement representation of -1). The number `-13.5` would be stored the same way, except now the exponent is `0x8001` (the sign bit is now 1 which means the number as a whole is negative, but the exponent itself is positive).
|
||||
The number `0.135` would be stored the same way,
|
||||
except now the exponent is `0x7FFF`
|
||||
(note that the sign bit is 0, and the bottom 15 bits are the 2's complement representation of -1).
|
||||
The number `-13.5` would be stored the same way, except now the exponent is `0x8001`
|
||||
(the sign bit is now 1 which means the number as a whole is negative, but the exponent itself is positive).
|
||||
|
||||
## Arithmetic
|
||||
- Addition is done the same way as it's done by hand, although in base-100 instead of decimal.
|
||||
@ -284,38 +453,58 @@ The number `0.135` would be stored the same way, except now the exponent is `0x7
|
||||
## Transcendental Functions
|
||||
- Logarithms are calculated similar to how it's described by the HP Journal article "Personal Calculator Algorithms IV: Logarithmic Functions" by William Egbert.
|
||||
- see `src/decn/proto/ln_mfp.cpp` for initial prototyping development work
|
||||
- Exponentials are calculated similar to the HP 35 algorithm, as described [here](http://www.jacques-laporte.org/expx.htm) using the same constants as the logarithm algorithm.
|
||||
- Exponentials are calculated similar to the HP 35 algorithm, as described [here](https://archived.hpcalc.org/laporte/expx.htm) using the same constants as the logarithm algorithm.
|
||||
- see `src/decn/proto/exp.cpp` for initial prototyping development work
|
||||
- Powers are calculated using the identity y^x = e^(x*ln(y))
|
||||
- Square roots are calculated using the identity sqrt(x) = e^(0.5*ln(x))
|
||||
- Square roots are calculated using a fixed number of Newton-Raphson iterations to calculatie 1/sqrt(x) and then multiplying by x.
|
||||
- the iteration for 1/sqrt(x) is new_estimate = 0.5*estimate * (3 - x * estimate * estimate)
|
||||
- see `src/decn/proto/recip_sqrt.cpp for initial prototyping development work
|
||||
- Trigonometric functions are calculated using algorithms similar to the [sinclair scientific](http://files.righto.com/calculator/sinclair_scientific_simulator.html), and are fairly slow and inaccurate.
|
||||
|
||||
## TODO
|
||||
- Trigonometric functions could be implemented with algorithms similar to those described in the HP Journal articles "Personal Calculator Algorithms II: Trigonometric Functions" and "Personal Calculator Algorithms III: Inverse Trigonometric Functions", both by William Egbert.
|
||||
- will probably assign to the shifted `1`, `2`, and `3` keys, and `-` for calculating inverse trig functions.
|
||||
- Trigonometric functions could be implemented with algorithms similar to those used in Valentin Albillo's [implementation](http://www.hpcc.org/datafile/hp12/12c_TrigonometryFunctions.pdf) for the HP 12C, but would take more flash
|
||||
- These could also use the implementation described in the HP Journal articles "Personal Calculator Algorithms II: Trigonometric Functions" and "Personal Calculator Algorithms III: Inverse Trigonometric Functions", both by William Egbert. This would likely take even more flash though.
|
||||
- Special cases, such as taking the logarithms of numbers near 1, negative number raised to integer powers, etc. could be implemented separately, similar to what is described in the HP Journal note "The New Accuracy: Making 2^3 = 8" by Dennis Harms.
|
||||
- The display blanking for trailing 0s assumes that 16 digits will actually be displayed, but this might not be the case if the negative sign, decimal point, or exponents are displayed
|
||||
- Would be nice to have the `hex <=> dec` converter from the original firmware if there is more flash space
|
||||
- Would be nice to have the resistor color band decoder if there is more flash space
|
||||
- Rounding: currently, to save code space, there is no rounding being done (even for intermediate steps), and numbers are instead truncated. Still, with 18 digits of precision (two guard digits, even if all 16 digits are actually displayed), the results are fairly accurate.
|
||||
- Square roots could be more-accurately implemented using digit-by-digit methods similar to those described in the HP Journal article "Personal Calculator Algorithms I: Square Roots" by William Egbert.
|
||||
- calculating using Newton-Raphson iterations for the reciprocal square root 1/sqrt(x), and then multiplying by the original value would probably also be more accurate, and definitely much faster
|
||||
- the iteration for the reciprocal square root is new_estimate = 0.5 * estimate * (3 - x * estimate * estimate)
|
||||
- Reciprocal/division could also be more-accurately implemented using digit-by-digit methods (the Newton-Raphson iterations currently used are quite fast though).
|
||||
|
||||
# Key Debouncing
|
||||
The keyboard matrix is scanned once every 5ms. The keyboard debouncing is based on the quick draw/integrator hybrid algorithm described [here](https://summivox.wordpress.com/2016/06/03/keyboard-matrix-scanning-and-debouncing/). This algorithm combines the advantages of both methods:
|
||||
The keyboard matrix is scanned once every 5ms.
|
||||
The keyboard debouncing is based on the quick draw/integrator hybrid algorithm described
|
||||
[here](https://summivox.wordpress.com/2016/06/03/keyboard-matrix-scanning-and-debouncing/).
|
||||
This algorithm combines the advantages of both methods:
|
||||
|
||||
1. It signals a key press immediately, the very first instant a keyboard matrix scan detects a key is pressed (similar to the "quick-draw" method).
|
||||
1. It has an "integrator" to determine both when a key is fully pressed and when a key is fully released. This prevents the mechanically bouncy keys from registering multiple times when pressed.
|
||||
1. It has an "integrator" (a saturating up/down counter) to determine both when a key is fully pressed and when a key is fully released. This prevents the mechanically bouncy keys from registering multiple times when pressed.
|
||||
|
||||
In practice, the keyboard debouncing works much better than the original firmware (which would occasionally miss keystrokes).
|
||||
In practice, the keyboard debouncing works much better than the original firmware
|
||||
(which would occasionally miss keystrokes).
|
||||
|
||||
# Implementation on an STC 8051 Microcontroller
|
||||
This was my 1st time using an 8051 microcontroller. The architecture is a bit limiting for programming in "high-level" languages such as C compared to more modern architectures -- even compared to other 8-bit architectures such as the AVR (used in the arduino). Most significantly, there is no stack-pointer-relative addressing, which makes C functions takes up a lot of code space, since they have to emulate stack-pointer-relative addressing. Unfortunately, the microcontroller used only has 13K of code space. The compiler used (SDCC) also does not support using a 2nd data pointer, even though STC's implementation of the 8051 has one.
|
||||
This was my 1st time using an 8051 microcontroller.
|
||||
The architecture is a bit limiting for programming in "high-level" languages such as C compared to more modern architectures
|
||||
-- even compared to other 8-bit architectures such as the AVR (used in the arduino).
|
||||
Most significantly, there is no stack-pointer-relative addressing,
|
||||
which makes C functions takes up a lot of code space,
|
||||
since they have to emulate stack-pointer-relative addressing.
|
||||
Unfortunately, the microcontroller used only has 13K of code space.
|
||||
The compiler used (SDCC) also does not support using a 2nd data pointer,
|
||||
even though STC's implementation of the 8051 has one.
|
||||
|
||||
I've avoided relying on the functions being able to be re-entrant, so that they do not depend on having a stack. SDCC is *not* set to use `--stack-auto` to reduce code size (this means functions are not re-entrant). Some "large" local variables are declared as static in functions to save on the code space needed to emulate a stack. I used a lot more globals than I what I would typically like to have used, and a lot less pointers passed to functions, since these are extremely expensive (to account for the 3 different memory types).
|
||||
I've avoided relying on the functions being able to be re-entrant,
|
||||
so that they do not depend on having a stack.
|
||||
SDCC is *not* set to use `--stack-auto` to reduce code size (this means functions are not re-entrant).
|
||||
Some "large" local variables are declared as static in functions to save on the code space needed to emulate a stack.
|
||||
I used a lot more globals than what I would typically like to have used,
|
||||
and a lot less pointers passed to functions,
|
||||
since these are extremely expensive (to account for the 3 different memory types).
|
||||
|
||||
Another weird thing about the 8051 is that not all of the memory is addressed the same way. On this microcontroller, there are 512 bytes of ram total, of which:
|
||||
Another weird thing about the 8051 is that not all of the memory is addressed the same way.
|
||||
On this microcontroller, there are 512 bytes of ram total, of which:
|
||||
|
||||
- only 128 bytes can be addressed directly (or indirectly)
|
||||
- the start of this address space is also shared with general purpose registers, so you don't actually have the full 128 bytes of directly addressable memory
|
||||
@ -325,7 +514,9 @@ Another weird thing about the 8051 is that not all of the memory is addressed th
|
||||
- on the original 8051, this memory would have actually been external, but on this microcontroller the "external" ram is built in
|
||||
- addressing this memory is more difficult than addressing indirect memory, which is itself more difficult than addressing memory directly
|
||||
|
||||
Thus, there are special compiler directives to tell it what address space to place variables in memory. (Even for a simple calculator, there isn't enough directly addressable memory (128 bytes) to store everything.) General-purpose pointers and operations using general-purpose pointers are relatively expensive since the pointers must encode the memory type.
|
||||
Thus, there are special compiler directives to tell it what address space to place variables in memory.
|
||||
(Even for a simple calculator, there isn't enough directly addressable memory (128 bytes) to store everything.)
|
||||
General-purpose pointers and operations using general-purpose pointers are relatively expensive since the pointers must encode the memory type.
|
||||
|
||||
|
||||
# Licensing
|
||||
|
7
action.yml
Normal file
7
action.yml
Normal file
@ -0,0 +1,7 @@
|
||||
# GitHub Actions
|
||||
|
||||
name: 'STC RPN Calc CI build'
|
||||
description: 'run CI build in docker container'
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
@ -1,391 +0,0 @@
|
||||
:0400000002001332B5
|
||||
:03000B0002008967
|
||||
:09006C00751600751701751800E6
|
||||
:0300860002000E67
|
||||
:03000E0002017874
|
||||
:20008900C021C0E0C0F0C082C083C0D075D008120B22120BEC74FFB52202801A200007E58A
|
||||
:2000A90015B514028020E5142410F8A622E514045403F514C2007880860FBF0809788486CC
|
||||
:2000C9000FBF0802C2B2D0D0D083D082D0F0D0E0D02132438E80758AC5758C1DC28DD28C13
|
||||
:2000E900D2A9D2AF22AFB174FB5FF5B143B204D2B222C374019517E433FFB40100E433F5AB
|
||||
:200109008222751600751800900012E4F0900013F022C374019517B3E433FF7040900013EF
|
||||
:20012900E075F00AA4FF900012E0FE2FFF7405B51704C3E49FFFE5162401F582E43400F5E4
|
||||
:2001490083E4F09000A0EFF0EF3395E0A3F09000011225EF12010BE56360020563E5199091
|
||||
:200169002DEB93F58212282F75170175630022D2001200EE1208FD120AD21200DCC2B49099
|
||||
:200189000012E4F0900013F0902DFF120A2078808607BF080978848607BF0802C2B22000AA
|
||||
:2001A900EDE5152410F98719E515045403F515E514B51502D200E519902DEB93FFBF2A0368
|
||||
:2001C9000205A0BF2B030205A0BF2D030205A0BF2E030203A6BF2F030205A0BF3002805150
|
||||
:2001E900BF31030202B6BF32030202B6BF33030202B6BF34030202B6BF35030202B6BF3696
|
||||
:20020900030202B6BF37030202B6BF38030202B6BF39030202B6BF3C030205A0BF3D030256
|
||||
:20022900047DBF630302053EBF72030205A00205FE300205C2B202060374FC2517502EE525
|
||||
:2002490018700B900012E4F0751801020603900012E0FE900013F0900012E4F00518E51850
|
||||
:2002690024FD4003020603751801020603C374019517B3E433FE6013751702E5162401F5AB
|
||||
:2002890082E43400F583EFF0020603E516700302060374F025165003020603E5162401F5CE
|
||||
:2002A90082E43400F583EFF0051602060330025FC374019517B3E433FE7040900013E07539
|
||||
:2002C900F00AA4FE900012E0FD2EFE7405B51704C3E49EFEE5162401F582E43400F583E437
|
||||
:2002E900F09000A0EEF0EE3395E0A3F09000011225EF12010BE56360020563E519902DEB41
|
||||
:2003090093F58212282F75170175630002060374FC2517503DE5187013E519902DEB9324DB
|
||||
:20032900D0FE900012F0751801020603900012E0900013F0E519902DEB9324D0FE900012D9
|
||||
:20034900F00518E51824FD4003020603751801020603C374019517B3E433FE601D751702CB
|
||||
:20036900E5162401FDE43400FEE519902DEB93FC8D828E83F0051602060374F025165003E4
|
||||
:20038900020603E5162401FDE43400FEE519902DEB93FC8D828E83F0051602060330025F1A
|
||||
:2003A900C374019517B3E433FE7040900013E075F00AA4FE900012E0FD2EFE7405B5170450
|
||||
:2003C900C3E49EFEE5162401F582E43400F583E4F09000A0EEF0EE3395E0A3F090000112FC
|
||||
:2003E90025EF12010BE56360020563E519902DEB93F58212282F751701756300020603C364
|
||||
:2004090074019517B3E433FE6028AE160516EE2401F582E43400F5837430F0AE160516EE08
|
||||
:200429002401F582E43400F583742EF07517030206037402B5172CE5167011AE160516EEA4
|
||||
:200449002401F582E43400F5837430F0AE160516EE2401F582E43400F583742EF0751703B9
|
||||
:20046900020603E51724FB4005051702060375170402060330025FC374019517B3E433FE09
|
||||
:200489007040900013E075F00AA4FE900012E0FD2EFE7405B51704C3E49EFEE5162401F5C3
|
||||
:2004A90082E43400F583E4F09000A0EEF0EE3395E0A3F09000011225EF12010BE563600297
|
||||
:2004C9000563E519902DEB93F58212282F751701756300020603C374019517B3E433FE7006
|
||||
:2004E90040900013E075F00AA4FE900012E0FD2EFE7405B51704C3E49EFEE5162401F58251
|
||||
:20050900E43400F583E4F09000A0EEF0EE3395E0A3F09000011225EF12010BE563600205B3
|
||||
:2005290063E519902DEB93F58212282F75170175630102060320020BC374019517B3E433EA
|
||||
:20054900FE6019C20275630112010B751700E519902DEB93F58212282F02060374FC251704
|
||||
:2005690050111517751800900012E4F0900013F0020603E51670030206031516E516240180
|
||||
:20058900F582E43400F583E0FEBE2E028003020603751702020603C374019517B3E433FEAC
|
||||
:2005A9007040900013E075F00AA4FE900012E0FD2EFE7405B51704C3E49EFEE5162401F5A2
|
||||
:2005C90082E43400F583E4F09000A0EEF0EE3395E0A3F09000011225EF12010BE563600276
|
||||
:2005E9000563E519902DEB93F58212282F75170175630080058F8212282F751C0075820085
|
||||
:200609001209A9C374019517B3E433FF7004E5636016122661AE82AF837D008E828F838D07
|
||||
:20062900F01222C7AF82801412264EAD82AE837C008D828E838CF01222C7AF82EF700B75F8
|
||||
:200649001D1090001F1209EB8065751D0D90001FC0071209EBD007EF30E710758201C00703
|
||||
:20066900120A42D007C3E49FFF800A758200C007120A42D007C2D575F00AEF30E704B2D5E3
|
||||
:20068900F4048430D502F4042430F582C007120A42D00775F00AEFC2D530E704D2D5F40460
|
||||
:2006A90084E5F030D502F4042430F582120A42758200120A937401B51702800302075312D6
|
||||
:2006C900264EAD82AE837C008D828E838CF01222C7E582FF700C751D1090001F1209EB02EF
|
||||
:2006E90007FD751D0D90001FC0071209EBD007EF30E710758201C007120A42D007C3E49FAB
|
||||
:20070900FF800A758200C007120A42D007C2D575F00AEF30E704B2D5F4048430D502F40442
|
||||
:200729002430F582C007120A42D00775F00AEFC2D530E704D2D5F40484E5F030D502F404E2
|
||||
:200749002430F582120A420207FDE5167009758230120A420207FD74FC2517402A7F00C30A
|
||||
:20076900EF951640030207FDBF100040030207FDEF2401F582E43400F583E0F582C007122A
|
||||
:200789000A42D0070F80D87F00C3EF9516501CBF0D005017EF2401F582E43400F583E0F55B
|
||||
:2007A90082C007120A42D0070F80DEBF0D005012BF0D005016758220C007120A42D0070FC3
|
||||
:2007C90080EE751C0D7582011209A97405B51708758201120A428006758200120A4290003A
|
||||
:2007E90013E02430F582120A42900012E02430F582120A42758201120A9330020675825EF5
|
||||
:08080900120A42C2B402019779
|
||||
:202DEB00633C726D2F3938372A3635342D3332312B3D2E305354432052504E202020202087
|
||||
:152E0B002020202043616C63756C61746F722076312E313000D2
|
||||
:20081100AF82AEB0741F5EF5B0758232C007120E69D00753070FEFC454F0F5A075826412F0
|
||||
:200831000E69D2B5758264120E69C2B522E582FFC4540FF582C007120811D0078F82120834
|
||||
:2008510011020894AFA0C2B7D2B6D2B5439580AE96747F5EF596758264C007120E69A2A795
|
||||
:200871009201AE95747F5EF595439680C2B5D2B5758264120E69D007C2B58FA0A201E43344
|
||||
:20089100F582227E007F00C007C006120855E582D006D007700122758201C007C006120E69
|
||||
:2008B1005AD006D0070EBE00010FC3EE9464EF940040D422AF82C007120894D007C2B5D21C
|
||||
:2008D100B7C2B674F05FF5A0D2B5758264C007120E69D007C2B553070FEFC454F0F5A0D239
|
||||
:2008F100B5758264120E69C2B50208947595007596FFAFB1740F5FF5B143B2F075821E1231
|
||||
:200911000E5A758203120811758205120E5A758203120811758264120E6975820312081195
|
||||
:20093100758264120E69758202120811758264120E6975820612083E75820C12083E758213
|
||||
:200951001412083E75822812083E75824012083E7F00758200C0071208C5D007EF6002745C
|
||||
:200971000FFE8E82C0071208C57582001208C575821C1208C57582101208C57582181208CC
|
||||
:20099100C57582101208C575821C1208C5D0070FBF020040BD020AC5AF82BF0200501D7461
|
||||
:2009B100F0251C4017EF030354C02480251CF582C00712083ED0078F1A851C1B22E582FF56
|
||||
:2009D100700B75828012083E751A0080097582C012083E751A01751B0022AE82AD837F0074
|
||||
:2009F100AC1D8E828D838FF0122D5DFB6020EC601D8B82C007C006C005C004120A42D004A9
|
||||
:200A1100D005D006D0070EBE00010D1C80D422AE82AF838E828F83E493FD60148D82C00795
|
||||
:200A3100C006120A42D006D0070EBE00E60F80E322AF82BF0D028003BF0A05120AC5803E9F
|
||||
:200A5100E4BF090104FE7003EE6014E51A70087582011209CE80277582001209CE801F8FF4
|
||||
:200A7100821208C5051B74F0251B5012E51A70087582011209CE80067582001209CE900090
|
||||
:200A91000122AF82E51B6010EFB51A0C758220C007120A42D00780EC22E582540FFF24F633
|
||||
:200AB100400A8F0674302EF582020A4274572FF582020A4275820112083E751A00751B0081
|
||||
:010AD1002202
|
||||
:200AD2007591007592007590FFAFB174FC5FF5B1AFB274FC5FF5B243B003AFC974CF5FF542
|
||||
:200AF200C9AFCA74CF5FF5CA43C8307F00EF2F25E0248AFE7D00ED2EF9902E20E493FCF7DF
|
||||
:200B12000DBD040040F00FBF050040E17522FF227880760043B203AFB074FC5FF5B043B0ED
|
||||
:200B320003AFB274FC5FF5B27880860F30B0047E0080027E01EE2F7880F67880860F30B160
|
||||
:200B5200047E0080027E02EE2F7880F67880860F30CC047E0080027E04EE2F7880F67880E2
|
||||
:200B7200860F30CD047E0080027E08EE2F7880F67F00902E24E493FEC3EF9E505CEF042453
|
||||
:200B920080F87600EF04FE8FF005F07401800225E0D5F0FBFD7C0074042CF5F005F07401C8
|
||||
:200BB200800225E0D5F0FBF4F590ED5590FB70047A0180027A008A0BEE2480F9870A8CF07E
|
||||
:200BD20005F0EB800225E0D5F0FBFB2AF77590FF0CBC040040C10F8099227522FF75240076
|
||||
:200BF200E524252425E0FEFD248AF52CE5242485F52BE5242480F52A752500C00DE525258E
|
||||
:200C12002CFAA80A8628A82B860FE5252525FA8AF005F07403800225E0D5F0FBFA5FF529E2
|
||||
:200C3200E52575F002A4F5F005F0E5298002C313D5F0FBF529852826852927A82A860F85DB
|
||||
:200C520025F005F07A017B008006EA2AFAEB33FBD5F0F78F0D7F00ED520AEF520BD00DEAA2
|
||||
:200C72004B601B902E21E493FFC3E52864808FF063F08095F0501FE52804F5268018902ECB
|
||||
:200C920020E493FFC364808528F063F08095F05005E52814F526E52924FC5003020DF1E519
|
||||
:200CB2002975F003A4900CBB73020CC7020D07020D60020D9DC00D902E20E493FF3395E054
|
||||
:200CD200FB902E23E493FA3395E0FDEA2FFFED3BFBE526FA3395E0FDC3EA9FED64808BF093
|
||||
:200CF20063F08095F0D00D5003020DFD752600752701020DFD902E22E493FFC3E526648002
|
||||
:200D12008FF063F08095F0400D752702902E21E493F526020DFDC00DEF3395E0FBC3E49FDD
|
||||
:200D3200FFE49BFBE526FA3395E0FDC3EF9AEB64808DF063F08095F0D00D5003020DFD75DD
|
||||
:200D52002700902E20E493F5260523020DFDC00D902E21E493FF3395E0FB902E23E493FA9F
|
||||
:200D72003395E0FDEFC39AFFEB9DFBE526FA3395E0FDC3EF9AEB64808DF063F08095F0D084
|
||||
:200D92000D40687526007527038060C00D902E22E493FFFA3395E0FBC3E49AFAE49BFBE518
|
||||
:200DB20026FC3395E0FDC3EA9CEB64808DF063F08095F0D00D400C752700902E20E493F55E
|
||||
:200DD200268028C3E52664808FF063F08095F0401A752702902E21E493F5260523800C7518
|
||||
:200DF2002700902E20E493F52605237401B52902800A7401B52705E5252EF522ED248A25DE
|
||||
:200E120025F8A626E5242485F9870FE5252525FC8CF005F07403800225E0D5F0FBF4FB52D6
|
||||
:200E32000F8CF005F0E527800225E0D5F0FBFC4FF7052574FC25254003020C0D052474FBB1
|
||||
:080E520025244003020BF222EB
|
||||
:052E2000E21E020204A5
|
||||
:1C0E5A0075F00A74E6D5E0FDD5F0F8D582F222000000000000D582F722D2B422C1
|
||||
:09007500753800753900753A0078
|
||||
:200E7600AD82AE83AFF0AA70AB71AC728A828B838CF0122D5DF8A3122D5DF98D828E838FF8
|
||||
:200E9600F0E8122CD8A3E9122CD874022DFDE43EFE74022AF574E43BF5758C76757300E58B
|
||||
:200EB600732DF8E43EF98F04C005C006C007E5732574FAE43575FBAF768A828B838FF01240
|
||||
:200ED6002D5DFA888289838CF0122CD80573C3E5739409D007D006D00540C422AD82122D8A
|
||||
:200EF6005DFEA3122D5DFF30E60C8E048F058C8274804DF583228E82747F5FF58322AD82E7
|
||||
:200F1600AE83AFF0E572600BAB70AC7174804CF571800353717F8D828E838FF0E570122C53
|
||||
:200F3600D8A3E571022CD8AD82AE83AFF074022DFDE43EFEAC70BC09005015EC2DF9E43E8B
|
||||
:200F5600FA8F0389828A838BF0E4122CD80C80E622AD82AE83AFF0753A00E4F539F538F5EC
|
||||
:200F76003B74022DFDE43EFEE53B2DFAE43EFB8F048A828B838CF0122D5D75F00A84F53817
|
||||
:200F9600E53B2DFAE43EFB8F048A828B838CF0122D5D75F00A8485F039E53B2DFAE43EFB0D
|
||||
:200FB6008F04E53A75F00AA42538F98A828B838CF0122CD885393A053B74F7253B50A92236
|
||||
:200FD600AD82AE83AFF0753A00753900753800753B0874022DFDE43EFEE53B2DFAE43EFB16
|
||||
:200FF6008F048A828B838CF0122D5D75F00A84F538E53B2DFAE43EFB8F048A828B838CF069
|
||||
:20101600122D5D75F00A8485F039E53B2DFAE43EFB8F04E53975F00AA4253AF98A828B83E3
|
||||
:201036008CF0122CD885383A153B7401253B50A92285823C85833D85F03E122D5DA3122D18
|
||||
:201056005D33E433F540853C82853D83853EF0120EF28582418583427402253CF8E4353D9A
|
||||
:20107600F9AC3E7B00EB28FAE439FE8C078A828E838FF0122D5D70060BBB090040E7EB753D
|
||||
:20109600F002A4D39541F4B3F541E54295F0F542EB605ABB090050557402253CFDE4353D03
|
||||
:2010B600FEAF3E7543008B3F74F7253F4030E5432DF544E43EF5458F46E53F2DFAE43EFB47
|
||||
:2010D6008F048A828B838CF0122D5DFA8544828545838546F0122CD80543053F80CA854334
|
||||
:2010F60070853C82853D83853EF0120F3D7402253CFDE4353DFEAF3E8D828E838FF0122DDE
|
||||
:201116005DFDBD0A005015853C82853D83853EF0120FD6154174FFB541021542854170852E
|
||||
:201136004271854072853C82853D83853EF0020F148582478583487549007C008C4A8C4BCA
|
||||
:201156008C4C854782854883E0FB700990002D75F04002136CBB2D06754C02754901AB4968
|
||||
:20117600EB2547F582E43548F583E0F54F742EB54F14E54C20E006434C0102136890002DD3
|
||||
:2011960075F040021415C3E54F648094B15003021223C374B9854FF063F08095F05003025E
|
||||
:2011B6001223BC12005020EC30E016ECC313242FF9E54A75F00AA4FFE54F24D0FE2FF78079
|
||||
:2011D60006E54F24D0F54A0CE54B700F7401B54C0280057403B54C03754BFFE54C7005757F
|
||||
:2011F6004C04801C7401B54C05754C0580127402B54C05754C0680087403B54C03754C070C
|
||||
:20121600E54C30E003021368054B021368EB2547F582E43548F583E0FFBF305AC37483851C
|
||||
:201236004CF063F08095F0E433FE601DBC12005017EC30E010ECC313FA242FF9E54A75F095
|
||||
:201256000AA4F78003754A000CE54C30E01DEE6003021368E54B7006754BFE021368E54B48
|
||||
:2012760020E703021368154B021368EE7003021368054B021368EF600302135FC374838544
|
||||
:201296004CF063F08095F0400990002D75F04002136C90003BE0F54DA3E0F54EAA4DAF4ED1
|
||||
:2012B600EC30E00FECC313FE242FF9E54A75F00AA4F70CECC313F57090002D75F040C0076C
|
||||
:2012D600C002120F3DD002D007C37480854BF063F08095F05016E54BFD3395E0FE1DBDFF4E
|
||||
:2012F600011EED254DFAEE354EFF8014E54B30E70FE54BFD3395E0FEED254DFAEE354EFF6A
|
||||
:20131600C374FF9A74BF8FF063F08095F0400AEA9401EF64809440500990002D75F04002B0
|
||||
:201336001415C3E54C64809486E433FEB40100E433F5728A708F7190002D75F040120F14A3
|
||||
:2013560090002D75F04002104790002D75F0400214150B021176AD82AE83AFF0E4122CD8A2
|
||||
:20137600A3122CD874022DFDE43EFE7C00EC2DF9E43EFA8F0389828A838BF0E4122CD80C09
|
||||
:20139600BC090040E822AD82AE83AFF074022DFDE43EFE7C00EC2DF9E43EFA8F0389828A98
|
||||
:2013B600838BF0122D5D6004758200220CBC090040E375820122AD82AE83AFF0122D5DFB5C
|
||||
:2013D600A3122D5DFCBB0005BCC00280047582002274022DFDE43EFE7C00EC2DF9E43EFA77
|
||||
:2013F6008F0389828A838BF0122D5DF9B9FF028004758200220CBC090040DF75820122AD0F
|
||||
:2014160082AE83AFF0E4122CD8A374C0122CD874022DFDE43EFE7C00EC2DF9E43EFA8F0381
|
||||
:2014360089828A838BF074FF122CD80CBC090040E722AD82AE83AFF0C007C006C0051213EA
|
||||
:20145600CCE582D005D006D0076001228D828E838FF0122D5DFBA3122D5DFC902E3CE4935C
|
||||
:20147600F9740193FAE96203EA62048D828E838FF0EB122CD8A3EC022CD87F0075702D8F68
|
||||
:201496007175724090003D75F000C007120E7675709E75710075724090004875F000120E22
|
||||
:2014B6007690003D75F00012104790004875F000121047D007E4FEFDF550F551F552F5538F
|
||||
:2014D600BE09005063EF7023EE243FF582E43400F583ED244AFBE43400FCE0FA8B828C8342
|
||||
:2014F600E0FBC3EA9B50047FFF8023EF7020EE243FF582E43400F583ED244AFBE43400FCFD
|
||||
:20151600E0FA8B828C83E0FBC39A50027F010E0D74022550F550E43551F55174022552F5D8
|
||||
:2015360052E43553F553809890003D75F000C007120EF2AD82AE83ED2550FDEE3551FE90AB
|
||||
:20155600004875F000C006C005120EF2AB82AC83D005D006D007EB2552FBEC3553FCC3EBD2
|
||||
:201576009DEC64808EF063F08095F0500475820122C3ED9BEE64808CF063F08095F050045F
|
||||
:201596007582FF228F8222AD82AE83AFF0C007C006C005120EF2AB82AC83D005D006D007A9
|
||||
:2015B600EBB55405ECB55501228D828E838FF0C007C006C005C004C003120F67D003D0045C
|
||||
:2015D600D005D006D0070BBB00D60C80D375570090002D75F04012104790009E75F04012FC
|
||||
:2015F600104790002D75F040120EF2AD82AE8390009E75F040C006C005120EF2AB82AC83DE
|
||||
:20161600D005D006EDB50306EEB50402801890002D75F040120EF285825485835590009EC3
|
||||
:2016360075F04012159D755608E556242FF9E55624A0F886058D037C00AA577F00EA2BFBB3
|
||||
:20165600EF3CFC87078F027E00C3EA9BEE64808CF063F08095F0400CE5572DD39FF4FE7534
|
||||
:201676005700800E74642FFFE5572DD39FF4FE755701E556242FF8A6061556E55630E7A937
|
||||
:201696002275580090009E75F04012139CE58260012290002D75F04012139CE58260127556
|
||||
:2016B600709E75710075724090002D75F040020E7675709E7571007572409000A975F040A3
|
||||
:2016D600120E76E52E33E433FE605E789E860408E6FD20E754121490AD82BD01051215E3AD
|
||||
:2016F6008035BDFF2975702D75710075724090009E75F040120E767570A975710075724017
|
||||
:2017160090002D75F040120E761215E3800990002D75F04012136C7570A97571007572409A
|
||||
:2017360090009E75F040020E76EE705E789E860408E6FE30E754121490AD82BD01051215B8
|
||||
:20175600E38035BDFF2975702D75710075724090009E75F040120E767570A9757100757213
|
||||
:201776004090002D75F040120E761215E3800990002D75F04012136C7570A975710075723A
|
||||
:201796004090009E75F040020E7690002D75F04012104790009E75F04012104790002D7561
|
||||
:2017B600F040120EF2AC82AE8390009E75F040C006C004120EF2AA82AB83D004D006C3EA52
|
||||
:2017D6009CEB64808EF063F08095F0501B90002D75F040120EF285825485835590009E7578
|
||||
:2017F600F04012159D0218A290002D75F040120EF2AC82AE8390009E75F040C006C00412E1
|
||||
:201816000EF2AA82AB83D004D006C3EC9AEE64808BF063F08095F050737E0090009E75F0EC
|
||||
:2018360040C006120EF2AB82AC8390002D75F040C004C003120EF2AA82AF83D003D004D04E
|
||||
:2018560006EBC39AFBEC9FFCEEFA3395E0FFC3EA9BEF64808CF063F08095F0501090002D07
|
||||
:2018760075F040C006120F67D0060E80AE90009E75F040120EF2858270858371E52E33E44E
|
||||
:2018960033F57290002D75F040120F147F08EF242FF9EF24A0F886068704EE2C2558FE7573
|
||||
:2018B600F06484E5F0F775F064EE84F5581FEF30E7DCE558604290002D75F040120EF2AEE4
|
||||
:2018D60082AF83E52E33E433FD90002D75F040C007C006C005120F67D005D006D007740AA8
|
||||
:2018F600252FF52F74012EF570E43FF5718D7290002D75F040120F147570A97571007572D8
|
||||
:201916004090009E75F040020E767F0090002D75F040C0071213CCE582D007701190009E92
|
||||
:2019360075F040C0071213CCE582D007600990002D75F0400214159000A975F040C0071249
|
||||
:20195600136C90002D75F04012104790009E75F040121047D007AE2E7D00530680789E8646
|
||||
:20197600030886047B00530480EB6205EC6206ED4E60027401F55A90002D75F040C0071228
|
||||
:201996000EF2AC82AD8390009E75F040C005C004120EF2AA82AB83D004D005D007EA2CF580
|
||||
:2019B6005BEB3DF55C755908E55924A0F97A08EA24ABF886068E057E00EA242FFCC000A8FB
|
||||
:2019D600048604D00087038BF0ECA42DFDEE35F0FE8F037C00EB2DFDEC3EFE7570648C7132
|
||||
:2019F6008D828E83C006C005C002C001C000122D10AB82D000D001D002D005D006A603752B
|
||||
:201A160070647571008D828E83C002C001122CAFAD82AE83D001D0028D071AEA30E790E53F
|
||||
:201A360059601A9000A975F040C007120F679000A975F040120F67D00778ABA6071559E530
|
||||
:201A56005920E7030219BEBF0A0040249000A975F040C007120F679000A975F040120F6774
|
||||
:201A7600D007055BE4B55B02055C78ABA607801FEF601C9000A975F040C007120F67D007E4
|
||||
:201A9600EF75F00AA4FF78AB8606EF2E78ABF6C3E55B94FFE55C648094BF5025C3740195FA
|
||||
:201AB6005B7440855CF063F08095F05014855B70855C71855A729000A975F040120F1480EE
|
||||
:201AD6000990002D75F0400214157570A975710075724090002D75F040120E7690002D7595
|
||||
:201AF600F04002104790002D75F04012139CE582600990002D75F04002141590002D75F0A5
|
||||
:201B16004012104775702D7571007572409000BF75F040120E7690002D75F040120EF2AE3B
|
||||
:201B360082AF83C3E49EFEE49FFFEE24FFF570EF34FFF571E52E33E433F5729000B475F0AB
|
||||
:201B560040120F14AF2FBF1400500678B67632801ABF2100500678B6761E800FBF320050BB
|
||||
:201B76000678B67614800478B6760A7F01EF24B6F876000FBF090040F47570B475710075A9
|
||||
:201B9600724090002D75F040120E767F007570BF75710075724090009E75F040C007120E9B
|
||||
:201BB6007612192090002D75F04012144875702675712E75728090009E75F040120E76127D
|
||||
:201BD60016977570B475710075724090009E75F040120E7612192012169775702D75710031
|
||||
:201BF6007572409000B475F040120E76D0070FBF060040992275702D7571007572409000D4
|
||||
:201C16001475F000120E7675709E75710075724090002D75F040120E76121AFB7570147582
|
||||
:201C3600710075720090009E75F040120E76021920E52E20E70D90002D75F04012139CE563
|
||||
:201C560082600990002D75F04002141590002D75F04012104790002D75F040120EF2E58250
|
||||
:201C76008583F02401FEE435F0FF78BFA60608A607E4F52DF52E75702675712E7572809054
|
||||
:201C9600009E75F040120E76789E760108760090002D75F04012144812169775702D7571C3
|
||||
:201CB600007572409000B475F040120E767F00EF600D9000B475F040C007120FD6D007759A
|
||||
:201CD60070B475710075724090002D75F040C007120E76D0077E00E52E30E703021D867562
|
||||
:201CF600702D7571007572409000B475F040C007C006120E7675702D757100757240900069
|
||||
:201D16009E75F040120E76D006D0077D00C3ED9F501890009E75F040C007C006C005120FAD
|
||||
:201D360067D005D006D0070D80E3C007C006121697D006D00774F6252F502B90002D75F0E0
|
||||
:201D560040C007C006120EF2AC82AD83D006D007C3E49C74808DF063F08095F05008E52F0B
|
||||
:201D760024F6F52F8006752DFF752EFF0E021CEDEF24C1F9EE14F70FBF09005003021CC55A
|
||||
:201D96007570B475710075724090002D75F040120E767F08EF75F00BA4243EFD742E35F0DF
|
||||
:201DB600FEEF24C1F97C008703C3EC9B50318D708E7175728090009E75F040C007C006C0EE
|
||||
:201DD60005C004C001120E76789E7600087600121697D001D004D005D006D0070C80C890F9
|
||||
:201DF600002D75F040C007120F67D0071FBF090040A290002D75F04012144875702D757144
|
||||
:201E1600007572409000B475F040120E7690002D75F04012136C78BF860608E6FF30E71339
|
||||
:201E3600755D01C3E49EFEE49FFF78BFA60608A6078003755D0078BF8606088607C3EE946A
|
||||
:201E560010EF648094A740607570107571278E828F83122DAFAB828B2F78BF868208868365
|
||||
:201E7600757010757127122D79AB82AC8378BFA60308A6047570647571008B828C83C00495
|
||||
:201E9600C003122DAFAA82D003D0048A307570647571008B828C83122D79AC82AD838C31D0
|
||||
:201EB600752D05752E008042C3EE9464EF64809480402F7570647571008E828F83122DAFC2
|
||||
:201ED600AC828C2F78BF8682088683757064757100122D79AC82AD838C30752D03752E006A
|
||||
:201EF60080088E2F752D01752E00E55D600990002D75F04012144875703175712E75728035
|
||||
:201F160090009E75F040120E761219207570B475710075724090009E75F040120E760216D0
|
||||
:201F360097121C4775703175712E75728090009E75F040120E7675702D75710075724090D6
|
||||
:201F5600001475F000120E7675709E75710075724090002D75F040120E76121AFB757014B4
|
||||
:201F760075710075720090009E75F040120E76021920755F0090002D75F0401213CCE5824C
|
||||
:201F9600600990002D75F040021415E52E30E70C90002D75F040121448755F0175702D75D3
|
||||
:201FB60071007572409000B475F040120E7690009E75F04012136C78A0761D78A1762F78AF
|
||||
:201FD6009E760208760090009E75F040121448121697E52E20E70990002D75F040021415A7
|
||||
:201FF6007570B475710075724090002D75F040120E7675703175712E75728090009E75F009
|
||||
:2020160040120E7675702D7571007572409000B475F040120E7675702675712E7572809020
|
||||
:20203600002D75F040120E76752D01752E0012192075702D75710075724090009E75F0409F
|
||||
:20205600120E7690009E75F0401214487570B475710075724090002D75F040120E767E0077
|
||||
:20207600E52E20E71C75702D7571007572409000B475F040C006120E76121697D0060E808D
|
||||
:20209600DF7D00EE24FFF570ED34FFF57190000A122CF3E5828583F078BFF608A6F07570F8
|
||||
:2020B600B475710075724090002D75F040120E7675703175712E75728090009E75F04012DB
|
||||
:2020D6000E7690009E75F0401214487EFF7D00E52E20E72075702D7571007572409000B48E
|
||||
:2020F60075F040C006C005120E76121697D005D0060D80DBBEFF1F78BF86030886048D0275
|
||||
:202116007F001ABAFF011FEA2BFBEF3CFC78BFA60308A6048007EE24C1F9ED14F77570B48A
|
||||
:2021360075710075724090002D75F040C006120E76D0060EBE0900502DEE75F00BA4243E32
|
||||
:20215600FD742E35F0FF8D708F7175728090009E75F040C006120E7690009E75F04012141A
|
||||
:2021760048D0060220E375702675712E75728090009E75F040120E76121697757026757187
|
||||
:202196002E75728090009E75F040120E76789E76010876007FFFEF24C1F9E4BFFF0104FE30
|
||||
:2021B600755E00EE600978BF8603088604800687028A037C00AA5E7D00C3EA9BED64808C4B
|
||||
:2021D600F063F08095F05013C007C006C001121920D001D006D007055E80C80FBF09005055
|
||||
:2021F6002CEF700D78A07614789E760008760080A5BF010678A0760B809C90009E75F04012
|
||||
:20221600C007120F67D00778A0760A8089E55F6003021AFB2275703175712E7572809000E0
|
||||
:202236009E75F040120E76121920021F8890009E75F04012139CE582601275702675712E2F
|
||||
:2022560075728090002D75F040020E7690002D75F04012139CE582600990002D75F04002C2
|
||||
:20227600136C75709E75710075724090001475F000120E76121C477570147571007572005F
|
||||
:2022960090009E75F040120E76121920021F8890001F7445F09000207472F0900021F090BC
|
||||
:2022B6000022746FF09000237472F0900024E4F022AD82AE83AFF07C008C617A008D828E61
|
||||
:2022D600838FF0C007C006C005C004C0021213CCE582D002D004D005D006D00760071222F3
|
||||
:2022F600A5758200228D708E718F7290005375F000C004C002120E7690005375F00012103F
|
||||
:2023160047D002D004900055E0700F90001F7430F0900020E4F075820022900053E0FEA332
|
||||
:20233600E0FF30E70890001F742DF07C0190005375F000C004C002120EF2AE82AF83D002B8
|
||||
:20235600D004902E25E493FDF8790018B8FF0119C3E89EE964808FF063F08095F0400AEEBD
|
||||
:2023760094FDEF6480947F50027A01EA7057EF30E753EC241FF582E43400F5837430F00C23
|
||||
:202396008C010CE9241FF582E43400F583742EF0C3E49EF8E49FF918B8FF01198C62C3E492
|
||||
:2023B60098748089F063F08095F05017E562241FF582E43400F5837430F0056218B8FF01E7
|
||||
:2023D6001980DBAC62EC241FF8E43400F9900055E075F00A842430FB88828983F00CEA60CA
|
||||
:2023F600128C030CEB241FF582E43400F583742EF08019EE4F70108C030CEB241FF582E4D9
|
||||
:202416003400F583742EF01EBEFF011FEC241FF9E43400FB900055E075F00A84A8F074303E
|
||||
:2024360028F889828B83F0900055E0FB75F00A84E5F0700AEA7004EF30E7037561010CEA27
|
||||
:202456007019EE4F70108C030CEB241FF582E43400F583742EF01EBEFF011FEDC313FD758E
|
||||
:202476006001C3E5609D400302255CEC241FF8E43400F9E5602455F582E43400F583E07528
|
||||
:20249600F00A842430FB88828983F00CEA7019EE4F70108C030CEB241FF582E43400F58347
|
||||
:2024B600742EF01EBEFF011FEC241FF9E43400FBE5602455F582E43400F583E075F00A84A6
|
||||
:2024D600A8F0743028F889828B83F00CEA7019EE4F70108C030CEB241FF582E43400F58375
|
||||
:2024F600742EF01EBEFF011FE5602455F9E43400FB89828B83E07025EA7004EF30E71EEA75
|
||||
:20251600700BC3EE94FEEF6480947F500605610561802EBEFE2BBFFF2805618024E56024F1
|
||||
:2025360055F582E43400F583E0FB75F00A84E5F0700CEA7004EF30E7057561018003756171
|
||||
:20255600000560022478EA700EC3E49E74808FF063F08095F04005ECC39561FCEC241FF5E0
|
||||
:2025760082E43400F583E4F090005375F000C002120EF2AE82AF83D002EA6023C374809E4D
|
||||
:2025960074808FF063F08095F0400AEE9480EF6480947F50071222A5758200228E82227538
|
||||
:0325B6008200227E
|
||||
:202E25001000000A0000000000000000000017023A325C63282D440080FF7F451F2F1205EE
|
||||
:202E45003B5E3509FE7F5F1F014F502B185600FD7F633221083510505254FC7F635F00218F
|
||||
:202E65001E53351F43FB7F636332002121082121FA7F63635F000021211D5FF97F6363634A
|
||||
:1C2E8500320000210523F87F6363635F0000024C28F77F6363636332000F62415B
|
||||
:08007E00756300756400C20205
|
||||
:2025B9007403556475F00BA42474FE740035F0FF7D0074032564540375F00BA42474FB74A1
|
||||
:2025D9000035F0FC8B708C718D728E828F838DF0120E76056422AE82AF83E5637002156475
|
||||
:2025F9009000A0E0FCA3E0FD90003BECF0EDA3F08E828F831211477403556475F00BA4241B
|
||||
:2026190074FE740035F0FF7D0075702D8D717572408E828F838DF0020E767403556475F029
|
||||
:202639000BA42474FE740035F0FF7D008E828F838DF002136C7403556475F00BA42474F536
|
||||
:2026590082740035F0F58322E56404540375F00BA42474F582740035F0F58322AE82AF8350
|
||||
:20267900E56404540375F00BA42474FC740035F0FD7B008C828D838BF0C007C0061213CCCD
|
||||
:20269900E582D006D00770277403556475F00BA42474FC740035F0FD7B008C828D838BF0F4
|
||||
:2026B900C007C0061213CCE582D006D007601FE56404540375F00BA42474FC740035F0FD0E
|
||||
:2026D9007B008C828D838BF01214150227837403556475F00BA42474FC740035F0FD8C707C
|
||||
:2026F9008D7175720090006975F000C007C006120E76E56404540375F00BA42474FC74009B
|
||||
:2027190035F0FD8C708D7175720090002D75F040120E767403556475F00BA42474FC740059
|
||||
:2027390035F0FD8C708D7175720090009E75F040120E76D006D007C007C0068E828F8312A6
|
||||
:202759000011D006D007E56404540375F00BA42474FE740035F0FF7D0075702D8D71757248
|
||||
:20277900408E828F838DF0120E760225B9AE82AF837403556475F00BA42474FC740035F018
|
||||
:20279900FD7B008C828D838BF0C007C0061213CCE582D006D0076001227403556475F00B5A
|
||||
:2027B900A42474FC740035F0FD8C708D7175720090006975F000C007C006120E7674035504
|
||||
:2027D9006475F00BA42474FC740035F0FD8C708D7175720090002D75F040120E76D006D0BF
|
||||
:2027F90007C007C0068E828F83120011D006D0077403556475F00BA42474FE740035F0FFC8
|
||||
:202819007D0075702D8D717572408E828F838DF0020E76B20222AF82C007120E73D007BFCF
|
||||
:202839002A030228D0BF2B028055BF2D030228D6BF2E0302298CBF2F03022900BF340302ED
|
||||
:202859002B86BF3503022B8FBF3603022B9CBF3703022BC3BF3803022BB6BF3903022BA9A3
|
||||
:20287900BF3C030229CEBF3D03022906BF63030229B3BF6D03022B83BF7203022AE22230A2
|
||||
:20289900022F7401B56302800215647403556475F00BA42474FE740035F0FF7D0075706927
|
||||
:2028B9007571008D728E828F838DF0120E76C20222901697022675901920022675740355F3
|
||||
:2028D9006475F00BA42474FE740035F0FF7D008E828F838DF0121448901697122675900035
|
||||
:2028F9006975F000021448901C0B02267530022F7401B56302800215647403556475F00BB4
|
||||
:20291900A42474FE740035F0FF7D0075705E7571008D728E828F838DF0120E76C202227498
|
||||
:2029390003556475F00BA42474FE740035F0FF7D008E828F838DF01213CCE5826001221574
|
||||
:20295900647403556475F00BA42474FE740035F0FF7D00E56404540375F00BA42474FB744C
|
||||
:202979000035F0FC8B708C718D728E828F838DF0020E76200201227403556475F00BA42454
|
||||
:2029990074FE740035F0FF8E708F7175720090005E75F000120E76C202227403556475F0CB
|
||||
:2029B9000BA42474FE740035F0FF7D008E828F838DF002136C100203022AA77403556475F7
|
||||
:2029D900F00BA42474FE740035F0FF7D008E828F838DF012139CE5826001227403556475A5
|
||||
:2029F900F00BA42474FE740035F0FF7D008E828F838DF01213CCE582600122740355647555
|
||||
:202A1900F00BA42474FE740035F0FF8E708F7175720090006975F000120E76740355647552
|
||||
:202A3900F00BA42474FE740035F0FF8E708F7175720090002D75F040120E76E52E30E71B8E
|
||||
:202A59007403556475F00BA42474FE740035F0FF7D008E828F838DF002141590009E75F011
|
||||
:202A79004012136C78A076051222437403556475F00BA42474FE740035F0FF7D0075702D61
|
||||
:202A99008D717572408E828F838DF0020E767403556475F00BA42474FE740035F0FF7D00E4
|
||||
:202AB9008E828F838DF01213CCE5826001227403556475F00BA42474FE740035F0FF7D0094
|
||||
:202AD9008E828F838DF00214481002028006901AFB0227867403556475F00BA42474FE74A4
|
||||
:202AF9000035F0FF7D008E828F838DF01213CCE5826001227403556475F00BA42474FE7454
|
||||
:202B19000035F0FF8E708F7175720090006575F040120E767403556475F00BA42474FE7415
|
||||
:202B39000035F0FF7D00E56404540375F00BA42474FB740035F0FC8B708C718D728E828F65
|
||||
:202B5900838DF0120E76E56404540375F00BA42474FE740035F0FF7D007570658D71757234
|
||||
:202B7900408E828F838DF0020E7602282C200201220564C2022220020122901F88122786B2
|
||||
:202B9900C202222002012290222B122786C2022220020122901F37122786C202222002017C
|
||||
:202BB90022901C47122786C20222E56404540375F00BA42474FE740035F0FF7D008E828F40
|
||||
:202BD900838DF01213CCE582701F7403556475F00BA42474FE740035F0FF7D008E828F83E4
|
||||
:202BF9008DF01213CCE582601FE56404540375F00BA42474FE740035F0FF7D008E828F83E3
|
||||
:202C19008DF0121415022CA97403556475F00BA42474FE740035F0FF8E708F717572009025
|
||||
:202C3900006975F000120E76E56404540375F00BA42474FE740035F0FF8E708F717572004C
|
||||
:202C590090002D75F040120E767403556475F00BA42474FE740035F0FF8E708F717572000C
|
||||
:202C790090009E75F040120E76122243E56404540375F00BA42474FE740035F0FF7D007583
|
||||
:162C9900702D8D717572408E828F838DF0120E761225B9C2022258
|
||||
:202CAF007A10E4FBFCE58225E0F582E58333F583EB33FBEC33FCEB9570F5F0EC9571400669
|
||||
:092CCF00FCABF0438201DADD22C6
|
||||
:06004200E478FFF6D8FD92
|
||||
:200020007900E94400601B7A00902EA178A275A000E493F2A308B8000205A0D9F4DAF27516
|
||||
:02004000A0FF1F
|
||||
:1B2CD80020F71130F6138883A88220F509F6A8837583002280FEF280F5F022FB
|
||||
:1D2CF300E5828570F0A4C582C0F08571F0A4D0F025F0C5838570F0A42583F583226B
|
||||
:202D1000E570457160467A01E57025E0F570E571334012F571E5829570E583957140030A50
|
||||
:202D300080E6C3E57113F571E57013F570C3E5829570F5F0E58395714005F58385F082C3C5
|
||||
:0D2D5000E57113F571E57013F570DAE122FD
|
||||
:200048007800E84400600A790175A000E4F309D8FC78A1E84400600C7901900001E4F0A314
|
||||
:04006800D8FCD9FAED
|
||||
:0F001100E4737581C9122DE7E582600302000ECA
|
||||
:1C2D5D0020F71430F6148883A88220F507E6A88375830022E280F7E49322E02285
|
||||
:202D7900C2D5E58330E70DD2D5E4C39582F582E49583F583E57130E70BE4C39570F570E45A
|
||||
:162D99009571F571122D1030D50BE4C39582F582E49583F583228E
|
||||
:202DAF00C2D5E58330E70DD2D5E4C39582F582E49583F583E57130E70DB2D5E4C39570F5EF
|
||||
:182DCF0070E49571F571122CAF30D50BE4C39582F582E49583F5832264
|
||||
:042DE70075820022CF
|
||||
:00000001FF
|
BIN
qt_gui.png
BIN
qt_gui.png
Binary file not shown.
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 71 KiB |
@ -121,7 +121,7 @@ ApplicationWindow
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: 16
|
||||
color: "gray"
|
||||
text: {getShiftedText(parent.parent.objectName, index) + "<br><br>"}
|
||||
text: {getShiftedUpText(parent.parent.objectName, index) + "<br><br>"}
|
||||
textFormat: Text.RichText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@ -132,6 +132,14 @@ ApplicationWindow
|
||||
textFormat: Text.RichText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
Text {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: 16
|
||||
color: "gray"
|
||||
text: {"<br><br>" + getShiftedDownText(parent.parent.objectName, index)}
|
||||
textFormat: Text.RichText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
MouseArea {
|
||||
//get row/column
|
||||
onClicked: _calculator.buttonClicked(parent.parent.objectName + "," + index)
|
||||
@ -155,18 +163,30 @@ ApplicationWindow
|
||||
return "<b>" + keys[row][col] + "</b>"
|
||||
}
|
||||
|
||||
function getShiftedText(row, col) {
|
||||
function getShiftedUpText(row, col) {
|
||||
var shifted_keys = [
|
||||
["Shift", "1/x", " √<span style=\"text-decoration: overline\">x</span> ", "CL<i>x</i>"],
|
||||
["y<sup>x</sup> ", "ln(x)", "log(x)", ""],
|
||||
["🔃", "e<sup>x</sup>", "10<sup>x</sup>", ""],
|
||||
["", "", "", ""],
|
||||
["y<sup>x</sup> ", "ln(x)", "log(x)", "π"],
|
||||
["R▼", "e<sup>x</sup>", "10<sup>x</sup>", ""],
|
||||
["sin(x)", "cos(x)", "tan(x)", "►deg"],
|
||||
["off", "STO", "RCL", "LAST<i>x</i>"]
|
||||
]
|
||||
|
||||
return "<small>" + shifted_keys[row][col] + "</small>"
|
||||
}
|
||||
|
||||
function getShiftedDownText(row, col) {
|
||||
var shifted_keys = [
|
||||
["", "", "", ""],
|
||||
["", "", "", ""],
|
||||
["R▲", "", "", ""],
|
||||
["asin(x)", "acos(x)", "atan(x)", "►rad"],
|
||||
["", "", "", ""]
|
||||
]
|
||||
|
||||
return "<small>" + shifted_keys[row][col] + "</small>"
|
||||
}
|
||||
|
||||
function getBackgroundColor(row, col) {
|
||||
var background_color = [
|
||||
["white", "white", "white", "#ff9494"],
|
||||
|
140
src/calc.c
140
src/calc.c
@ -21,6 +21,11 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include "calc.h"
|
||||
#include "stack_debug.h"
|
||||
|
||||
#ifdef DESKTOP
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
__xdata dec80 StoredDecn;
|
||||
__xdata dec80 LastX;
|
||||
@ -33,7 +38,8 @@ __xdata dec80 LastX;
|
||||
#define STACK_T 3
|
||||
|
||||
uint8_t NoLift = 0;
|
||||
__bit IsShifted = 0;
|
||||
__bit IsShiftedUp = 0;
|
||||
__bit IsShiftedDown = 0;
|
||||
|
||||
//stack "grows" towards 0
|
||||
__xdata dec80 Stack[STACK_SIZE]; //0->x, 1->y, 2->z, 3->t initially
|
||||
@ -87,10 +93,6 @@ static void do_unary_op(void (*f_ptr)(void)){
|
||||
}
|
||||
}
|
||||
|
||||
static void toggle_shifted(void){
|
||||
IsShifted ^= 1;
|
||||
}
|
||||
|
||||
void process_cmd(char cmd){
|
||||
//turn off backlight before start of processing
|
||||
backlight_off();
|
||||
@ -98,12 +100,11 @@ void process_cmd(char cmd){
|
||||
switch(cmd){
|
||||
//////////
|
||||
case '+':{
|
||||
if (IsShifted){ // LastX
|
||||
if (IsShiftedUp){ // LastX
|
||||
if (NoLift != 1){
|
||||
StackPtr--;
|
||||
}
|
||||
copy_decn(&stack(STACK_X), &LastX);
|
||||
IsShifted = 0;
|
||||
} else { // +
|
||||
do_binary_op(add_decn);
|
||||
}
|
||||
@ -114,22 +115,35 @@ void process_cmd(char cmd){
|
||||
} break;
|
||||
//////////
|
||||
case '-':{
|
||||
negate_decn(&stack(STACK_X));
|
||||
do_binary_op(add_decn);
|
||||
negate_decn(&LastX); //stored LastX was after negation of X
|
||||
if (IsShiftedUp) {
|
||||
do_unary_op(to_degree_decn);
|
||||
} else if (IsShiftedDown) {
|
||||
do_unary_op(to_radian_decn);
|
||||
} else {
|
||||
negate_decn(&stack(STACK_X));
|
||||
do_binary_op(add_decn);
|
||||
negate_decn(&LastX); //stored LastX was after negation of X
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '/':{
|
||||
do_binary_op(div_decn);
|
||||
if (IsShiftedUp){
|
||||
if (NoLift != 1){
|
||||
StackPtr--;
|
||||
}
|
||||
pi_decn();
|
||||
copy_decn(&stack(STACK_X), &AccDecn);
|
||||
} else {
|
||||
do_binary_op(div_decn);
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '=':{
|
||||
if (IsShifted){ //RCL
|
||||
if (IsShiftedUp){ //RCL
|
||||
if (NoLift != 1){
|
||||
StackPtr--;
|
||||
}
|
||||
copy_decn(&stack(STACK_X), &StoredDecn);
|
||||
IsShifted = 0;
|
||||
} else { //Enter
|
||||
if (!decn_is_nan(&stack(STACK_X))){
|
||||
StackPtr--;
|
||||
@ -139,9 +153,8 @@ void process_cmd(char cmd){
|
||||
} break;
|
||||
//////////
|
||||
case '.':{
|
||||
if (IsShifted){ //STO
|
||||
if (IsShiftedUp){ //STO
|
||||
copy_decn(&StoredDecn, &stack(STACK_X));
|
||||
IsShifted = 0;
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
@ -150,23 +163,8 @@ void process_cmd(char cmd){
|
||||
} break;
|
||||
//////////
|
||||
case '<':{ //use as +/- and sqrt
|
||||
if (IsShifted){ //take sqrt
|
||||
IsShifted = 0;
|
||||
if (decn_is_zero(&stack(STACK_X))){
|
||||
//sqrt(0) = 0
|
||||
} else if (!decn_is_nan(&stack(STACK_X))){
|
||||
copy_decn(&LastX, &stack(STACK_X)); //save LastX
|
||||
copy_decn(&AccDecn, &stack(STACK_X));
|
||||
if (AccDecn.exponent < 0){ //negative
|
||||
set_dec80_NaN(&stack(STACK_X));
|
||||
break;
|
||||
}
|
||||
//b = 0.5
|
||||
set_dec80_zero(&BDecn);
|
||||
BDecn.lsu[0] = 5;
|
||||
pow_decn();
|
||||
copy_decn(&stack(STACK_X), &AccDecn);
|
||||
}
|
||||
if (IsShiftedUp){ //take sqrt
|
||||
do_unary_op(sqrt_decn);
|
||||
} else { // +/-
|
||||
if (!decn_is_nan(&stack(STACK_X))){
|
||||
negate_decn(&stack(STACK_X));
|
||||
@ -175,73 +173,97 @@ void process_cmd(char cmd){
|
||||
} break;
|
||||
//////////
|
||||
case 'r':{ //use as swap and 1/x
|
||||
if (IsShifted){ //take 1/x
|
||||
IsShifted = 0;
|
||||
if (IsShiftedUp){ //take 1/x
|
||||
do_unary_op(recip_decn);
|
||||
} else { // swap
|
||||
if (!decn_is_nan(&stack(STACK_X))){
|
||||
dec80 tmp;
|
||||
copy_decn(&tmp, &stack(STACK_X));
|
||||
copy_decn(&AccDecn, &stack(STACK_X));
|
||||
copy_decn(&stack(STACK_X), &stack(STACK_Y));
|
||||
copy_decn(&stack(STACK_Y), &tmp);
|
||||
copy_decn(&stack(STACK_Y), &AccDecn);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case 'm':{ //use as shift
|
||||
toggle_shifted();
|
||||
if (IsShiftedUp) {
|
||||
IsShiftedUp = 0;
|
||||
IsShiftedDown = 1;
|
||||
} else if (IsShiftedDown) {
|
||||
IsShiftedUp = 0;
|
||||
IsShiftedDown = 0;
|
||||
} else {
|
||||
IsShiftedUp = 1;
|
||||
IsShiftedDown = 0;
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
//////////
|
||||
case '1':{
|
||||
if (IsShiftedUp){
|
||||
do_unary_op(sin_decn);
|
||||
} else if (IsShiftedDown){
|
||||
do_unary_op(arcsin_decn);
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '2':{
|
||||
if (IsShiftedUp){
|
||||
do_unary_op(cos_decn);
|
||||
} else if (IsShiftedDown){
|
||||
do_unary_op(arccos_decn);
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '3':{
|
||||
if (IsShiftedUp){
|
||||
do_unary_op(tan_decn);
|
||||
} else if (IsShiftedDown){
|
||||
do_unary_op(arctan_decn);
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '4':{
|
||||
if (IsShifted){ //roll down
|
||||
if (IsShiftedUp){ //roll down
|
||||
StackPtr++;
|
||||
IsShifted = 0;
|
||||
} else if (IsShiftedDown){ //roll up
|
||||
StackPtr--;
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '5':{
|
||||
if (IsShifted){ //e^x
|
||||
if (IsShiftedUp){ //e^x
|
||||
do_unary_op(exp_decn);
|
||||
IsShifted = 0;
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '6':{
|
||||
if (IsShifted){ //10^x
|
||||
if (IsShiftedUp){ //10^x
|
||||
do_unary_op(exp10_decn);
|
||||
IsShifted = 0;
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '9':{
|
||||
if (IsShifted){ //log10(x)
|
||||
if (IsShiftedUp){ //log10(x)
|
||||
do_unary_op(log10_decn);
|
||||
IsShifted = 0;
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '8':{
|
||||
if (IsShifted){ //ln(x)
|
||||
if (IsShiftedUp){ //ln(x)
|
||||
do_unary_op(ln_decn);
|
||||
IsShifted = 0;
|
||||
}
|
||||
} break;
|
||||
//////////
|
||||
case '7':{ //y^x
|
||||
if (decn_is_nan(&stack(STACK_Y)) || decn_is_nan(&stack(STACK_X))){
|
||||
set_dec80_NaN(&stack(STACK_Y));
|
||||
} else {
|
||||
copy_decn(&LastX, &stack(STACK_X)); //save LastX
|
||||
copy_decn(&AccDecn, &stack(STACK_Y));
|
||||
copy_decn(&BDecn, &stack(STACK_X));
|
||||
pow_decn();
|
||||
copy_decn(&stack(STACK_Y), &AccDecn);
|
||||
}
|
||||
pop();
|
||||
IsShifted = 0;
|
||||
do_binary_op(pow_decn);
|
||||
} break;
|
||||
//////////
|
||||
} //switch(cmd)
|
||||
IsShiftedUp = 0;
|
||||
IsShiftedDown = 0;
|
||||
#ifdef DESKTOP
|
||||
assert(TmpStackPtr == 0); // there should be no items on the temporaries stack after one global operation
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,7 +32,8 @@ void process_cmd(char cmd);
|
||||
//push_decn is equivalent to "set_x()" if no_lift is true
|
||||
void push_decn(__xdata const char* signif_str, __xdata exp_t exponent);
|
||||
extern uint8_t NoLift;
|
||||
extern __bit IsShifted;
|
||||
extern __bit IsShiftedUp;
|
||||
extern __bit IsShiftedDown;
|
||||
|
||||
void clear_x(void);
|
||||
__xdata dec80* get_x(void);
|
||||
|
@ -1,28 +1,46 @@
|
||||
add_library(Catch INTERFACE)
|
||||
if(EXISTS /usr/include/catch/catch.hpp)
|
||||
target_include_directories(Catch INTERFACE /usr/include/catch)
|
||||
elseif(EXISTS /usr/include/catch2/catch.hpp)
|
||||
target_include_directories(Catch INTERFACE /usr/include/catch2)
|
||||
else()
|
||||
endif()
|
||||
|
||||
#code coverage
|
||||
add_library(coverage_config INTERFACE)
|
||||
target_compile_options(coverage_config INTERFACE -O0 -g --coverage)
|
||||
target_link_libraries(coverage_config INTERFACE --coverage)
|
||||
|
||||
# decn library
|
||||
add_library(decn decn.c)
|
||||
add_library(decn decn.c ../utils.c)
|
||||
|
||||
# decn library with coverage
|
||||
add_library(decn_cover decn.c)
|
||||
target_link_libraries(decn_cover PUBLIC coverage_config)
|
||||
|
||||
add_executable(decn_test decn_test.c ../utils.c)
|
||||
target_link_libraries(decn_test decn_cover coverage_config Catch)
|
||||
# old tests (compare output with reference "golden" output file)
|
||||
add_executable(decn_test
|
||||
decn_test.c
|
||||
../utils.c
|
||||
)
|
||||
target_link_libraries(decn_test
|
||||
decn_cover
|
||||
coverage_config
|
||||
)
|
||||
|
||||
add_executable(decn_tests catch_main.cpp decn_tests.cpp ../utils.c)
|
||||
target_link_libraries(decn_tests decn_cover coverage_config mpfr Catch)
|
||||
# catch2 unit tests
|
||||
find_package(Catch2 REQUIRED)
|
||||
enable_testing()
|
||||
set (BUILD_TESTING ON)
|
||||
add_executable(decn_tests
|
||||
catch_main.cpp
|
||||
decn_tests.cpp
|
||||
decn_tests_div_sqrt.cpp
|
||||
decn_tests_transcendental.cpp
|
||||
decn_tests_trig.cpp
|
||||
../utils.c
|
||||
)
|
||||
target_link_libraries(decn_tests
|
||||
mpfr
|
||||
decn_cover
|
||||
coverage_config
|
||||
Catch2::Catch2
|
||||
)
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(decn_tests)
|
||||
|
||||
# decn prototyping
|
||||
add_subdirectory(proto)
|
||||
|
@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
422
src/decn/decn.c
422
src/decn/decn.c
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "../utils.h"
|
||||
#include "../stack_debug.h"
|
||||
|
||||
#include "decn.h"
|
||||
|
||||
@ -34,6 +35,7 @@
|
||||
// #define DEBUG_LOG_ALL //even more verbose
|
||||
// #define DEBUG_EXP
|
||||
// #define DEBUG_EXP_ALL //even more verbose
|
||||
// #define DEBUG_SQRT
|
||||
|
||||
#ifndef DESKTOP
|
||||
//#undef EXTRA_CHECKS
|
||||
@ -46,6 +48,7 @@
|
||||
#undef DEBUG_LOG_ALL
|
||||
#undef DEBUG_EXP
|
||||
#undef DEBUG_EXP_ALL
|
||||
#undef DEBUG_SQRT
|
||||
#endif
|
||||
|
||||
#ifdef DESKTOP
|
||||
@ -66,26 +69,61 @@ static const uint8_t num_digits_display = 16;
|
||||
|
||||
dec80 AccDecn;
|
||||
__idata dec80 BDecn;
|
||||
__idata dec80 TmpDecn; //used by add_decn() and mult_decn()
|
||||
__idata dec80 Tmp2Decn; //used by recip_decn() and ln_decn()
|
||||
__idata dec80 Tmp3Decn; //used by recip_decn() and ln_decn()
|
||||
__xdata dec80 Tmp4Decn; //used by div_decn() and pow_decn()
|
||||
__idata dec80 TmpDecn; //used by add_decn() and mult_decn() and sqrt_decn()
|
||||
__idata dec80 Tmp2Decn; //used by recip_decn(), ln_decn(), exp_decn(), sqrt_decn(), and sincos_decn()
|
||||
__idata dec80 Tmp3Decn; //used by ln_decn(), exp_decn(), sqrt_decn(), and sincos_decn()
|
||||
__xdata dec80 Tmp4Decn; //used by sincos_decn()
|
||||
|
||||
__xdata dec80 TmpStackDecn[4];
|
||||
#define TMP_STACK_SIZE (sizeof TmpStackDecn / sizeof TmpStackDecn[0])
|
||||
__idata uint8_t TmpStackPtr;
|
||||
|
||||
__xdata char Buf[DECN_BUF_SIZE];
|
||||
|
||||
//1 constant
|
||||
const dec80 DECN_1 = {
|
||||
0, {10, 0}
|
||||
};
|
||||
|
||||
//ln(10) constant
|
||||
const dec80 DECN_LN_10 = {
|
||||
0, {23, 2, 58, 50, 92, 99, 40, 45, 68}
|
||||
};
|
||||
|
||||
// pi
|
||||
const dec80 DECN_PI = {
|
||||
0, {31, 41, 59, 26, 53, 58, 97, 93, 24}
|
||||
};
|
||||
|
||||
// pi/2
|
||||
const dec80 DECN_PI2 = {
|
||||
0, {15, 70, 79, 63, 26, 79, 48, 96, 62}
|
||||
};
|
||||
|
||||
// 180/pi = 1rad in degree
|
||||
const dec80 DECN_1RAD = {
|
||||
1, {57, 29, 57, 79, 51, 30, 82, 32, 9}
|
||||
};
|
||||
|
||||
void st_push_decn(const dec80 * const src)
|
||||
{
|
||||
copy_decn(&TmpStackDecn[TmpStackPtr], src);
|
||||
TmpStackPtr++;
|
||||
assert(TmpStackPtr < TMP_STACK_SIZE);
|
||||
}
|
||||
|
||||
void st_pop_decn(dec80 * const dst)
|
||||
{
|
||||
assert(TmpStackPtr >= 1);
|
||||
TmpStackPtr--;
|
||||
if (dst) copy_decn(dst, &TmpStackDecn[TmpStackPtr]);
|
||||
}
|
||||
|
||||
void st_load_decn(dec80 * const dst)
|
||||
{
|
||||
assert(TmpStackPtr >= 1);
|
||||
copy_decn(dst, &TmpStackDecn[TmpStackPtr - 1]);
|
||||
}
|
||||
|
||||
void copy_decn(dec80* const dest, const dec80* const src){
|
||||
uint8_t i;
|
||||
|
||||
stack_debug(0x01);
|
||||
dest->exponent = src->exponent;
|
||||
|
||||
//copy nibbles
|
||||
@ -111,7 +149,7 @@ exp_t get_exponent(const dec80* const x){
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_exponent(dec80* acc, exp_t exponent, uint8_t num_is_neg){
|
||||
void set_exponent(dec80* acc, exp_t exponent, uint8_t num_is_neg){
|
||||
#ifdef EXP16
|
||||
if (num_is_neg){
|
||||
exponent |= 0x8000;
|
||||
@ -158,11 +196,12 @@ static void shift_left(dec80* x){
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_leading_zeros(dec80* x){
|
||||
void remove_leading_zeros(dec80* x){
|
||||
uint8_t digit100;
|
||||
uint8_t is_negative = (x->exponent < 0);
|
||||
exp_t exponent = get_exponent(x);
|
||||
|
||||
stack_debug(0x02);
|
||||
//find first non-zero digit100
|
||||
for (digit100 = 0; digit100 < DEC80_NUM_LSU; digit100++){
|
||||
if (x->lsu[digit100] != 0){
|
||||
@ -383,6 +422,11 @@ void set_dec80_zero(dec80* dest){
|
||||
}
|
||||
}
|
||||
|
||||
void set_decn_one(dec80* dest){
|
||||
set_dec80_zero(dest);
|
||||
dest->lsu[0] = 10;
|
||||
}
|
||||
|
||||
uint8_t decn_is_zero(const dec80* x){
|
||||
uint8_t i;
|
||||
for (i = 0; i < DEC80_NUM_LSU; i++){
|
||||
@ -586,6 +630,7 @@ void add_decn(void){
|
||||
return;
|
||||
}
|
||||
//save b for restoring later
|
||||
//n.b. don't use TmpStackDecn here, it is called quite often. So you'd need to increase TMP_STACK_SIZE
|
||||
copy_decn(&TmpDecn, &BDecn);
|
||||
//handle cases where signs differ
|
||||
if (AccDecn.exponent < 0 && BDecn.exponent >= 0){
|
||||
@ -792,7 +837,6 @@ void mult_decn(void){
|
||||
|
||||
void recip_decn(void){
|
||||
#define CURR_RECIP Tmp2Decn //copy of x, holds current 1/x estimate
|
||||
#define X_COPY Tmp3Decn //holds copy of original x
|
||||
uint8_t i;
|
||||
exp_t initial_exp;
|
||||
//check divide by zero
|
||||
@ -808,7 +852,7 @@ void recip_decn(void){
|
||||
//normalize
|
||||
remove_leading_zeros(&AccDecn);
|
||||
//store copy of x
|
||||
copy_decn(&X_COPY, &AccDecn);
|
||||
st_push_decn(&AccDecn);
|
||||
//get initial exponent of estimate for 1/x
|
||||
initial_exp = get_exponent(&AccDecn);
|
||||
#ifdef DEBUG_DIV
|
||||
@ -830,18 +874,16 @@ void recip_decn(void){
|
||||
} else {
|
||||
CURR_RECIP.lsu[0] = 10; //0.1 with implicit point and exponent
|
||||
}
|
||||
for (i = 1; i < DEC80_NUM_LSU; i++){
|
||||
CURR_RECIP.lsu[i] = 0;
|
||||
}
|
||||
zero_remaining_dec80(&CURR_RECIP, 1);
|
||||
copy_decn(&AccDecn, &CURR_RECIP);
|
||||
//do newton raphson iterations
|
||||
//do newton-raphson iterations
|
||||
for (i = 0; i < 6; i++){ //just fix number of iterations for now
|
||||
#ifdef DEBUG_DIV
|
||||
decn_to_str_complete(&curr_recip);
|
||||
decn_to_str_complete(&CURR_RECIP);
|
||||
printf("%2d: %s\n", i, Buf);
|
||||
#endif
|
||||
//Accum *= x_copy
|
||||
copy_decn(&BDecn, &X_COPY);
|
||||
st_load_decn(&BDecn);
|
||||
mult_decn();
|
||||
#ifdef DEBUG_DIV
|
||||
decn_to_str_complete(&AccDecn);
|
||||
@ -850,7 +892,7 @@ void recip_decn(void){
|
||||
//Accum *= -1
|
||||
negate_decn(&AccDecn);
|
||||
//Accum += 1
|
||||
copy_decn(&BDecn, &DECN_1);
|
||||
set_decn_one(&BDecn);
|
||||
add_decn();
|
||||
#ifdef DEBUG_DIV
|
||||
decn_to_str_complete(&AccDecn);
|
||||
@ -868,24 +910,20 @@ void recip_decn(void){
|
||||
//new_est(Accum) = recip + (1 - recip*x)*recip, where recip is current recip estimate
|
||||
copy_decn(&CURR_RECIP, &AccDecn);
|
||||
}
|
||||
st_pop_decn(0);
|
||||
|
||||
//try not to pollute namespace
|
||||
#undef CURR_RECIP
|
||||
#undef X_COPY
|
||||
}
|
||||
|
||||
inline void div_decn(void){
|
||||
#define ACC_COPY Tmp4Decn //holds copy of original acc
|
||||
void div_decn(void){
|
||||
//store copy of acc for final multiply by 1/x
|
||||
copy_decn(&ACC_COPY, &AccDecn);
|
||||
st_push_decn(&AccDecn);
|
||||
copy_decn(&AccDecn, &BDecn);
|
||||
recip_decn();
|
||||
//Accum now holds 1/x, multiply by original acc to complete division
|
||||
copy_decn(&BDecn, &ACC_COPY);
|
||||
st_pop_decn(&BDecn);
|
||||
mult_decn();
|
||||
|
||||
//try not to pollute namespace
|
||||
#undef ACC_COPY
|
||||
}
|
||||
|
||||
|
||||
@ -924,7 +962,7 @@ void ln_decn(void){
|
||||
printf("ln() accum scaled between 1,10: %s\n", Buf);
|
||||
#endif
|
||||
//get initial estimate (accum = 10 - A)
|
||||
copy_decn(&BDecn, &DECN_1);
|
||||
set_decn_one(&BDecn);
|
||||
BDecn.exponent = 1; //BDecn = 10
|
||||
negate_decn(&AccDecn);
|
||||
add_decn();
|
||||
@ -1056,7 +1094,7 @@ void ln_decn(void){
|
||||
#undef NUM_TIMES
|
||||
}
|
||||
|
||||
inline void log10_decn(void){
|
||||
void log10_decn(void){
|
||||
ln_decn();
|
||||
copy_decn(&BDecn, &DECN_LN_10);
|
||||
div_decn();
|
||||
@ -1067,8 +1105,8 @@ inline void log10_decn(void){
|
||||
void exp_decn(void){
|
||||
uint8_t j, k;
|
||||
uint8_t need_recip = 0;
|
||||
#define SAVED Tmp2Decn
|
||||
#define NUM_TIMES Tmp3Decn
|
||||
#define SAVED Tmp2Decn
|
||||
#define NUM_TIMES Tmp3Decn
|
||||
|
||||
//check not error
|
||||
if (decn_is_nan(&AccDecn)){
|
||||
@ -1101,7 +1139,7 @@ void exp_decn(void){
|
||||
//initial b = -10*ln(10)
|
||||
copy_decn(&BDecn, &DECN_LN_10); //b=ln(10)
|
||||
copy_decn(&SAVED, &AccDecn); //save = accum
|
||||
copy_decn(&AccDecn, &DECN_1);
|
||||
set_decn_one(&AccDecn);
|
||||
AccDecn.exponent = 1; //accum = 10
|
||||
mult_decn(); //accum = 10*ln(10)
|
||||
copy_decn(&BDecn, &AccDecn); //b = 10*ln(10)
|
||||
@ -1170,10 +1208,10 @@ void exp_decn(void){
|
||||
//build final value
|
||||
// (currently accum = save = remainder)
|
||||
// calculate 1+remainder
|
||||
copy_decn(&BDecn, &DECN_1);
|
||||
set_decn_one(&BDecn);
|
||||
add_decn();
|
||||
//get initial multiplier (10) for ln(10)
|
||||
copy_decn(&BDecn, &DECN_1);
|
||||
set_decn_one(&BDecn);
|
||||
BDecn.exponent = 1; //BDecn = 10
|
||||
//do multiplies
|
||||
j = UINT8_MAX; //becomes 0 after incrementing to start (1 + 10^-j) series
|
||||
@ -1226,16 +1264,16 @@ void exp_decn(void){
|
||||
#undef NUM_TIMES
|
||||
}
|
||||
|
||||
inline void exp10_decn(void){
|
||||
void exp10_decn(void){
|
||||
//exp10_decn() = exp_decn(AccDecn * ln(10))
|
||||
copy_decn(&BDecn, &DECN_LN_10);
|
||||
mult_decn();
|
||||
exp_decn();
|
||||
}
|
||||
|
||||
inline void pow_decn(void) {
|
||||
void pow_decn(void) {
|
||||
if (decn_is_zero(&BDecn)) {
|
||||
copy_decn(&AccDecn, &DECN_1);
|
||||
set_decn_one(&AccDecn);
|
||||
return;
|
||||
}
|
||||
if (decn_is_zero(&AccDecn)) {
|
||||
@ -1243,13 +1281,316 @@ inline void pow_decn(void) {
|
||||
return;
|
||||
}
|
||||
//calculate AccDecn = AccDecn ^ BDecn
|
||||
copy_decn(&Tmp4Decn, &BDecn); //save b
|
||||
st_push_decn(&BDecn);
|
||||
ln_decn();
|
||||
copy_decn(&BDecn, &Tmp4Decn); //restore b
|
||||
st_pop_decn(&BDecn);
|
||||
mult_decn(); //accum = b*ln(accum)
|
||||
exp_decn();
|
||||
}
|
||||
|
||||
#ifdef USE_POW_SQRT_IMPL
|
||||
void sqrt_decn(void) {
|
||||
if (decn_is_zero(&AccDecn)) {
|
||||
return;
|
||||
}
|
||||
if (decn_is_nan(&AccDecn)) {
|
||||
return;
|
||||
}
|
||||
if (AccDecn.exponent < 0){ //negative
|
||||
set_dec80_NaN(&AccDecn);
|
||||
return;
|
||||
}
|
||||
st_push_decn(&BDecn); // sqrt should behave like an unary operation
|
||||
//b = 0.5
|
||||
set_dec80_zero(&BDecn);
|
||||
BDecn.lsu[0] = 5;
|
||||
pow_decn();
|
||||
st_pop_decn(&BDecn);
|
||||
}
|
||||
#else
|
||||
void sqrt_decn(void){
|
||||
#define CURR_EST Tmp2Decn //holds current 1/sqrt(x) estimate
|
||||
#define X_2 Tmp3Decn //holds copy of original x / 2
|
||||
uint8_t i;
|
||||
exp_t initial_exp;
|
||||
if (decn_is_nan(&AccDecn)) {
|
||||
return;
|
||||
}
|
||||
if (AccDecn.exponent < 0){ //negative
|
||||
set_dec80_NaN(&AccDecn);
|
||||
return;
|
||||
}
|
||||
//normalize
|
||||
remove_leading_zeros(&AccDecn);
|
||||
#ifdef DEBUG_SQRT
|
||||
decn_to_str_complete(&AccDecn);
|
||||
printf("sqrt in: %s\n", Buf);
|
||||
#endif
|
||||
//store copy of x
|
||||
st_push_decn(&AccDecn);
|
||||
//calculate x_orig / 2
|
||||
set_dec80_zero(&BDecn);
|
||||
BDecn.lsu[0] = 5;
|
||||
mult_decn();
|
||||
copy_decn(&X_2, &AccDecn);
|
||||
//restore x
|
||||
st_load_decn(&AccDecn);
|
||||
//get initial estimate for 1/sqrt(x) == 10^(-0.5 * log(x)):
|
||||
// approximate significand == 10^(-0.5 * log(x_signif))
|
||||
// with linear approximation: -0.18 * x_signif + 2.5
|
||||
// new exponent part is (10^(-0.5 * log(10^x_exp)))
|
||||
// == 10^(-0.5 * x^exp)
|
||||
initial_exp = get_exponent(&AccDecn);
|
||||
set_exponent(&AccDecn, 0, 0); //clear exponent (Acc is not negative)
|
||||
#ifdef DEBUG_SQRT
|
||||
printf("sqrt exponent %d ", initial_exp);
|
||||
#endif
|
||||
if (initial_exp & 0x1){ //odd
|
||||
#ifdef DEBUG_SQRT
|
||||
printf("(odd) ");
|
||||
#endif
|
||||
//increment x_exp and
|
||||
initial_exp++;
|
||||
//approximate estimated significand as (-0.056*x_signif + 0.79) * 10^0.5
|
||||
// == -0.18 * x_signif + 2.5
|
||||
//b = -0.18
|
||||
BDecn.lsu[0] = 18;
|
||||
BDecn.exponent = -1; //negative, and exponent = -1
|
||||
//a = -0.18 * x_signif
|
||||
mult_decn();
|
||||
//b = 2.5
|
||||
BDecn.lsu[0] = 25;
|
||||
BDecn.exponent = 0;
|
||||
//a = -0.18 * x_signif + 2.5
|
||||
add_decn();
|
||||
} else { //even
|
||||
//keep x_exp as is and approximate estimated significand as
|
||||
// -0.056*x_signif + 0.79
|
||||
//b = -0.056
|
||||
BDecn.lsu[0] = 56;
|
||||
set_exponent(&BDecn, -2, 1);
|
||||
//a = -0.056 * x_signif
|
||||
mult_decn();
|
||||
//b = 0.79
|
||||
BDecn.lsu[0] = 7;
|
||||
BDecn.lsu[1] = 90;
|
||||
BDecn.exponent = 0;
|
||||
//a = -0.056*x_signif + 0.79
|
||||
add_decn();
|
||||
}
|
||||
//est_exp = -x_exp / 2;
|
||||
initial_exp = -initial_exp / 2;
|
||||
//est_exp-- if AccDecn exponent is negative
|
||||
// (AccDecn exponent is either 0 or -1, and AccDecn is positive)
|
||||
if (AccDecn.exponent != 0){
|
||||
initial_exp--;
|
||||
}
|
||||
set_exponent(&AccDecn, initial_exp, 0); //(initial estimate is never negative)
|
||||
copy_decn(&CURR_EST, &AccDecn);
|
||||
#ifdef DEBUG_SQRT
|
||||
printf(" -> %d\n", initial_exp);
|
||||
#endif
|
||||
//do newton-raphson iterations
|
||||
for (i = 0; i < 6; i++){ //just fix number of iterations for now
|
||||
#ifdef DEBUG_SQRT
|
||||
decn_to_str_complete(&CURR_EST);
|
||||
printf("sqrt %2d: %s\n", i, Buf);
|
||||
#endif
|
||||
//accum = est * est;
|
||||
copy_decn(&BDecn, &AccDecn);
|
||||
mult_decn();
|
||||
//accum *= x_orig_2; //accum = x/2 * est * est
|
||||
copy_decn(&BDecn, &X_2);
|
||||
mult_decn();
|
||||
//accum = - x/2 * est * est
|
||||
negate_decn(&AccDecn);
|
||||
//b = 3/2
|
||||
set_dec80_zero(&BDecn);
|
||||
BDecn.lsu[0] = 15;
|
||||
//accum = 3/2 - x/2 * est * est
|
||||
add_decn();
|
||||
//accum *= est; //accum = 0.5 * est * (3 - x * est * est)
|
||||
copy_decn(&BDecn, &CURR_EST);
|
||||
mult_decn();
|
||||
//est = accum;
|
||||
copy_decn(&CURR_EST, &AccDecn);
|
||||
}
|
||||
|
||||
//calc sqrt from recip_sqrt
|
||||
st_pop_decn(&BDecn);
|
||||
mult_decn();
|
||||
|
||||
#undef CURR_EST
|
||||
#undef X_COPY
|
||||
}
|
||||
#endif //USE_POW_SQRT_IMPL
|
||||
|
||||
|
||||
// normal angle to between 0 and 360 degrees
|
||||
void normalize_0_360(void) {
|
||||
const uint8_t is_negative = (AccDecn.exponent < 0);
|
||||
exp_t exponent;
|
||||
|
||||
remove_leading_zeros(&AccDecn);
|
||||
if (is_negative) {
|
||||
negate_decn(&AccDecn);
|
||||
}
|
||||
exponent = get_exponent(&AccDecn);
|
||||
//B = 360
|
||||
set_dec80_zero(&BDecn);
|
||||
BDecn.lsu[0] = 36;
|
||||
BDecn.exponent = 2;
|
||||
if (compare_magn() > 0) {
|
||||
do {
|
||||
do {
|
||||
//B = 3.6e...
|
||||
BDecn.exponent = exponent;
|
||||
if (compare_magn() >= 0) {
|
||||
negate_decn(&BDecn);
|
||||
add_decn();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
exponent--;
|
||||
} while (exponent >= 2);
|
||||
}
|
||||
|
||||
if (is_negative) {
|
||||
negate_decn(&AccDecn);
|
||||
//B = 360
|
||||
BDecn.exponent = 2;
|
||||
add_decn();
|
||||
}
|
||||
}
|
||||
|
||||
// K. Shirriff, "Reversing Sinclair's amazing 1974 calculator hack - half the ROM of the HP-35"
|
||||
// http://files.righto.com/calculator/sinclair_scientific_simulator.html
|
||||
#define SIN Tmp2Decn
|
||||
#define COS Tmp3Decn
|
||||
#define THETA Tmp4Decn
|
||||
void sincos_decn(const uint8_t sincos_arctan) {
|
||||
const uint8_t is_negative = AccDecn.exponent < 0;
|
||||
if (sincos_arctan) { //calculate arctan
|
||||
set_dec80_zero(&THETA);
|
||||
if (is_negative) negate_decn(&AccDecn);
|
||||
copy_decn(&COS, &AccDecn);
|
||||
set_decn_one(&SIN);
|
||||
} else { //calculate sin/cos
|
||||
normalize_0_360();
|
||||
to_radian_decn();
|
||||
copy_decn(&THETA, &AccDecn);
|
||||
set_decn_one(&COS);
|
||||
set_dec80_zero(&SIN);
|
||||
// 0.0 00 5
|
||||
SIN.lsu[2] = 50;
|
||||
negate_decn(&SIN);
|
||||
}
|
||||
do {
|
||||
if (sincos_arctan) { //calculate arctan
|
||||
// THETA is in AccDecn from previous iteration
|
||||
if (COS.exponent < 0) {
|
||||
if (is_negative) negate_decn(&AccDecn);
|
||||
break;
|
||||
}
|
||||
} else { //calculate sin/cos
|
||||
if (THETA.exponent < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// COS = COS - SIN / 1000
|
||||
copy_decn(&AccDecn, &COS);
|
||||
copy_decn(&BDecn, &SIN);
|
||||
shift_right(&BDecn);
|
||||
shift_right(&BDecn);
|
||||
shift_right(&BDecn);
|
||||
negate_decn(&BDecn);
|
||||
add_decn();
|
||||
copy_decn(&COS, &AccDecn);
|
||||
// SIN = SIN + COS / 1000
|
||||
copy_decn(&AccDecn, &SIN);
|
||||
copy_decn(&BDecn, &COS);
|
||||
shift_right(&BDecn);
|
||||
shift_right(&BDecn);
|
||||
shift_right(&BDecn);
|
||||
add_decn();
|
||||
copy_decn(&SIN, &AccDecn);
|
||||
// THETA = THETA -/+ 0.0 01
|
||||
copy_decn(&AccDecn, &THETA);
|
||||
set_dec80_zero(&BDecn);
|
||||
BDecn.lsu[1] = 1;
|
||||
if (!sincos_arctan) negate_decn(&BDecn);
|
||||
add_decn();
|
||||
copy_decn(&THETA, &AccDecn);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
void sin_decn(void) {
|
||||
sincos_decn(0);
|
||||
copy_decn(&AccDecn, &SIN);
|
||||
}
|
||||
|
||||
void cos_decn(void) {
|
||||
sincos_decn(0);
|
||||
copy_decn(&AccDecn, &COS);
|
||||
}
|
||||
|
||||
void tan_decn(void) {
|
||||
sincos_decn(0);
|
||||
copy_decn(&AccDecn, &SIN);
|
||||
copy_decn(&BDecn, &COS);
|
||||
div_decn();
|
||||
}
|
||||
|
||||
void arctan_decn(void) {
|
||||
sincos_decn(1);
|
||||
to_degree_decn();
|
||||
}
|
||||
|
||||
// see W.E. Egbert, "Personal Calculator Algorithms III: Inverse Trigonometric Functions"
|
||||
void arcsin_decn_rad(void) {
|
||||
st_push_decn(&AccDecn);
|
||||
copy_decn(&BDecn, &AccDecn);
|
||||
mult_decn();
|
||||
negate_decn(&AccDecn);
|
||||
set_decn_one(&BDecn);
|
||||
add_decn();
|
||||
sqrt_decn();
|
||||
recip_decn();
|
||||
st_pop_decn(&BDecn);
|
||||
mult_decn();
|
||||
sincos_decn(1);
|
||||
}
|
||||
|
||||
void arcsin_decn(void) {
|
||||
arcsin_decn_rad();
|
||||
to_degree_decn();
|
||||
}
|
||||
|
||||
void arccos_decn(void) {
|
||||
arcsin_decn_rad();
|
||||
negate_decn(&AccDecn);
|
||||
copy_decn(&BDecn, &DECN_PI2);
|
||||
add_decn();
|
||||
to_degree_decn();
|
||||
}
|
||||
#undef SIN
|
||||
#undef COS
|
||||
#undef THETA
|
||||
|
||||
void to_degree_decn(void) {
|
||||
copy_decn(&BDecn, &DECN_1RAD);
|
||||
mult_decn();
|
||||
}
|
||||
|
||||
void to_radian_decn(void) {
|
||||
copy_decn(&BDecn, &DECN_1RAD);
|
||||
div_decn();
|
||||
}
|
||||
|
||||
void pi_decn(void) {
|
||||
copy_decn(&AccDecn, &DECN_PI);
|
||||
}
|
||||
|
||||
static void set_str_error(void){
|
||||
Buf[0] = 'E';
|
||||
@ -1444,4 +1785,3 @@ void build_decn_at(dec80* dest, const char* signif_str, exp_t exponent){
|
||||
|
||||
#endif //DESKTOP
|
||||
|
||||
|
||||
|
@ -60,15 +60,21 @@ typedef struct {
|
||||
//remove sign bit, and return 15 bit exponent sign-extended to 16 bits
|
||||
exp_t get_exponent(const dec80* const x);
|
||||
|
||||
void set_exponent(dec80* acc, exp_t exponent, uint8_t num_is_neg);
|
||||
|
||||
void remove_leading_zeros(dec80* x);
|
||||
|
||||
|
||||
void copy_decn(dec80* const dest, const dec80* const src);
|
||||
|
||||
extern dec80 AccDecn;
|
||||
extern __idata dec80 BDecn;
|
||||
extern __xdata dec80 Tmp4Decn;
|
||||
extern __idata uint8_t TmpStackPtr;
|
||||
|
||||
void build_dec80(__xdata const char* signif_str, __xdata exp_t exponent);
|
||||
|
||||
void set_dec80_zero(dec80* dest);
|
||||
void set_decn_one(dec80* dest);
|
||||
void set_dec80_NaN(dec80* dest);
|
||||
uint8_t decn_is_zero(const dec80* x);
|
||||
uint8_t decn_is_nan(const dec80* x);
|
||||
@ -85,6 +91,17 @@ void log10_decn(void);
|
||||
void exp_decn(void);
|
||||
void exp10_decn(void);
|
||||
void pow_decn(void);
|
||||
void sqrt_decn(void);
|
||||
|
||||
void sin_decn(void);
|
||||
void cos_decn(void);
|
||||
void tan_decn(void);
|
||||
void arctan_decn(void);
|
||||
void arcsin_decn(void);
|
||||
void arccos_decn(void);
|
||||
void to_degree_decn(void);
|
||||
void to_radian_decn(void);
|
||||
void pi_decn(void);
|
||||
|
||||
//Buf should hold at least 18 + 4 + 5 + 1 = 28
|
||||
#define DECN_BUF_SIZE 28
|
||||
@ -103,6 +120,17 @@ void decn_to_str_complete(const dec80* x);
|
||||
void build_decn_at(dec80* dest, const char* signif_str, exp_t exponent);
|
||||
#endif
|
||||
|
||||
#ifdef DESKTOP
|
||||
#define PRINT_DEC80(n, v) \
|
||||
printf(n " %d %5d: ", v.exponent < 0, get_exponent(&v)); \
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++) { \
|
||||
printf("%02d ", v.lsu[i]); \
|
||||
} \
|
||||
fputc('\n', stdout);
|
||||
#else
|
||||
#define PRINT_DEC80(n, v)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -20,9 +20,6 @@
|
||||
#include <stdio.h>
|
||||
#include "decn.h"
|
||||
|
||||
extern char Buf[DECN_BUF_SIZE];
|
||||
|
||||
|
||||
static dec80 diff;
|
||||
|
||||
//diff = (acc - diff) / diff
|
||||
|
@ -21,20 +21,19 @@
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <boost/multiprecision/mpfr.hpp>
|
||||
#include <catch.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include "decn.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#include "decn_tests.h"
|
||||
|
||||
|
||||
namespace bmp = boost::multiprecision;
|
||||
using Catch::Matchers::Equals;
|
||||
|
||||
|
||||
|
||||
extern char Buf[DECN_BUF_SIZE];
|
||||
|
||||
|
||||
TEST_CASE("build decn"){
|
||||
build_dec80("0.0009234567890123456", 7);
|
||||
decn_to_str_complete(&AccDecn);
|
||||
@ -262,288 +261,6 @@ TEST_CASE("multiply"){
|
||||
CHECK_THAT(Buf, Equals("Error")); //acc*b
|
||||
}
|
||||
|
||||
static void div_test(
|
||||
//input
|
||||
const char* a_str, int a_exp,
|
||||
const char* b_str, int b_exp
|
||||
)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
CAPTURE(b_str); CAPTURE(b_exp);
|
||||
//do division
|
||||
build_dec80(a_str, a_exp);
|
||||
build_decn_at(&BDecn, b_str, b_exp);
|
||||
// decn_to_str_complete(&AccDecn);
|
||||
// printf(" acc: %s\n", Buf);
|
||||
// decn_to_str_complete(&BDecn);
|
||||
// printf(" b: %s\n", Buf);
|
||||
div_decn();
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // acc / b
|
||||
|
||||
//calculate actual result
|
||||
bmp::mpfr_float::default_precision(50);
|
||||
std::string a_full_str(a_str);
|
||||
a_full_str += "e" + std::to_string(a_exp);
|
||||
std::string b_full_str(b_str);
|
||||
b_full_str += "e" + std::to_string(b_exp);;
|
||||
// CAPTURE(a_full_str);
|
||||
// CAPTURE(b_full_str);
|
||||
bmp::mpfr_float a_actual(a_full_str);
|
||||
bmp::mpfr_float b_actual(b_full_str);
|
||||
a_actual /= b_actual; //calculate actual result
|
||||
if (decn_is_nan(&AccDecn)){
|
||||
//check that NaN result of division by 0
|
||||
CAPTURE(a_actual);
|
||||
CHECK(b_actual == 0);
|
||||
} else {
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
bmp::mpfr_float rel_diff = abs((a_actual - calculated) / a_actual);
|
||||
CHECK(rel_diff < 1e-17);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("division"){
|
||||
div_test(
|
||||
"1", 0,
|
||||
"0", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"3.14", 60,
|
||||
"-1.5", -2
|
||||
);
|
||||
|
||||
div_test(
|
||||
"4", 0,
|
||||
"4", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"1", 0,
|
||||
"3", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"500", 0,
|
||||
"99", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"500", 0,
|
||||
"2", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"3", 0,
|
||||
"25", -15
|
||||
);
|
||||
|
||||
div_test(
|
||||
"0.02", 0,
|
||||
"0.03", 0
|
||||
);
|
||||
}
|
||||
|
||||
static void log_test(
|
||||
//input
|
||||
const char* x_str, int x_exp,
|
||||
bool base10=false
|
||||
)
|
||||
{
|
||||
CAPTURE(x_str); CAPTURE(x_exp);
|
||||
CAPTURE(base10);
|
||||
build_dec80(x_str, x_exp);
|
||||
// decn_to_str_complete(&AccDecn);
|
||||
// printf(" acc: %s\n", Buf);
|
||||
if (base10){
|
||||
log10_decn();
|
||||
} else {
|
||||
ln_decn();
|
||||
}
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // log(x)
|
||||
|
||||
//calculate actual result
|
||||
bmp::mpfr_float::default_precision(50);
|
||||
std::string x_full_str(x_str);
|
||||
x_full_str += "e" + std::to_string(x_exp);
|
||||
CAPTURE(x_full_str);
|
||||
bmp::mpfr_float x_actual(x_full_str);
|
||||
CAPTURE(x_actual);
|
||||
if (decn_is_nan(&AccDecn)){
|
||||
//check that NaN is from result of log(-)
|
||||
CHECK(x_actual <= 0);
|
||||
} else {
|
||||
if (base10){
|
||||
x_actual = log10(x_actual);
|
||||
} else {
|
||||
x_actual = log(x_actual);
|
||||
}
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
bmp::mpfr_float rel_diff = abs((x_actual - calculated) / x_actual);
|
||||
CHECK(rel_diff < 3e-16); //TODO
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("log"){
|
||||
log_test("0", 0);
|
||||
log_test("-1", 0);
|
||||
log_test("0.155", 0);
|
||||
log_test("10", 0);
|
||||
log_test("1.1", 10);
|
||||
log_test("2.02", -10);
|
||||
log_test("2.02", 0);
|
||||
log_test("1.5", 0, true);
|
||||
log_test("9", 99);
|
||||
log_test("123", 12345);
|
||||
}
|
||||
|
||||
static void exp_test(
|
||||
//input
|
||||
const char* x_str, int x_exp,
|
||||
double epsilon=6e-16,
|
||||
bool base10=false
|
||||
)
|
||||
{
|
||||
CAPTURE(x_str); CAPTURE(x_exp);
|
||||
CAPTURE(base10);
|
||||
build_dec80(x_str, x_exp);
|
||||
if (base10){
|
||||
exp10_decn();
|
||||
} else {
|
||||
exp_decn();
|
||||
}
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // exp(x)
|
||||
CAPTURE(AccDecn.exponent);
|
||||
|
||||
//calculate actual result
|
||||
bmp::mpfr_float::default_precision(50);
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
std::string x_full_str(x_str);
|
||||
x_full_str += "e" + std::to_string(x_exp);
|
||||
bmp::mpfr_float x_actual(x_full_str);
|
||||
if (base10){
|
||||
x_actual *= log(10);
|
||||
}
|
||||
x_actual = exp(x_actual);
|
||||
CAPTURE(x_actual);
|
||||
bmp::mpfr_float rel_diff = abs((x_actual - calculated) / x_actual);
|
||||
CHECK(rel_diff < epsilon);
|
||||
}
|
||||
|
||||
static void exp10_test(
|
||||
//input
|
||||
const char* x_str, int x_exp,
|
||||
double epsilon=3e-15
|
||||
)
|
||||
{
|
||||
exp_test(x_str, x_exp, epsilon, true);
|
||||
}
|
||||
|
||||
TEST_CASE("exp"){
|
||||
exp_test("4.4", 0);
|
||||
exp_test("0.155", 0);
|
||||
exp_test("9.999", 0);
|
||||
exp_test("10", 0);
|
||||
exp_test("10.001", 0);
|
||||
exp_test("2.3", 2, 6e-15);
|
||||
exp_test("2.02", -10);
|
||||
exp_test("2.02", 0);
|
||||
exp_test("1.5", 0);
|
||||
exp_test("294.69999999", 0, 8e-15);
|
||||
|
||||
//do not operate on NaN
|
||||
set_dec80_NaN(&AccDecn);
|
||||
exp_decn();
|
||||
CHECK(decn_is_nan(&AccDecn)); //still NaN
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("exp10"){
|
||||
exp10_test("4.4", 0);
|
||||
exp10_test("0.155", 0);
|
||||
exp10_test("9.999", 0);
|
||||
exp10_test("10", 0);
|
||||
exp10_test("10.001", 0);
|
||||
exp10_test("2.02", -10);
|
||||
exp10_test("2.02", 0);
|
||||
exp10_test("1.5", 0);
|
||||
exp10_test("127", 0, 3e-14);
|
||||
}
|
||||
|
||||
static void pow_test(
|
||||
//input
|
||||
const char* a_str, int a_exp,
|
||||
const char* b_str, int b_exp
|
||||
)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
CAPTURE(b_str); CAPTURE(b_exp);
|
||||
|
||||
//compute power
|
||||
build_decn_at(&BDecn, b_str, b_exp);
|
||||
build_dec80(a_str, a_exp);
|
||||
|
||||
pow_decn();
|
||||
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // a^b
|
||||
|
||||
//calculate actual result
|
||||
bmp::mpfr_float::default_precision(50);
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
std::string a_full_str(a_str);
|
||||
a_full_str += "e" + std::to_string(a_exp);
|
||||
std::string b_full_str(b_str);
|
||||
b_full_str += "e" + std::to_string(b_exp);;
|
||||
// CAPTURE(a_full_str);
|
||||
// CAPTURE(b_full_str);
|
||||
bmp::mpfr_float a_actual(a_full_str);
|
||||
bmp::mpfr_float b_actual(b_full_str);
|
||||
a_actual = pow(a_actual, b_actual);
|
||||
if (decn_is_zero(&AccDecn)) {
|
||||
bmp::mpfr_float diff = abs(a_actual - calculated);
|
||||
CHECK(diff < 3e-14);
|
||||
} else {
|
||||
bmp::mpfr_float rel_diff = abs((a_actual - calculated)/a_actual);
|
||||
CHECK(rel_diff < 3e-14);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("power"){
|
||||
pow_test(
|
||||
"3.14", 60,
|
||||
"-1.5", -2
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"3", 0,
|
||||
"201", 0
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"5", 0,
|
||||
"0", 0
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"5", 0,
|
||||
"0", 2
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"0", 0,
|
||||
"5", 0
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"0", 0,
|
||||
"0", 0
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE("u32str corner"){
|
||||
u32str(0, &Buf[0], 10);
|
||||
CHECK_THAT(Buf, Equals("0"));
|
||||
|
28
src/decn/decn_tests.h
Normal file
28
src/decn/decn_tests.h
Normal file
@ -0,0 +1,28 @@
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
* decn_tests.h
|
||||
*
|
||||
* Created on: Oct 26, 2020
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DECN_TESTS_H_
|
||||
#define DECN_TESTS_H_
|
||||
|
||||
|
||||
static const int NUM_RAND_TESTS = 123456;
|
||||
|
||||
|
||||
#endif
|
200
src/decn/decn_tests_div_sqrt.cpp
Normal file
200
src/decn/decn_tests_div_sqrt.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
* decn_tests_div_sqrt.cpp
|
||||
*
|
||||
* Unit tests using https://github.com/catchorg/Catch2
|
||||
*
|
||||
* separate out reciprocal/division and sqrt tests
|
||||
*
|
||||
* Created on: Oct 26, 2020
|
||||
*/
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <boost/multiprecision/mpfr.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include "decn.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#include "decn_tests.h"
|
||||
|
||||
|
||||
namespace bmp = boost::multiprecision;
|
||||
using Catch::Matchers::Equals;
|
||||
|
||||
|
||||
static void div_test(){ //acc / b
|
||||
bmp::mpf_float::default_precision(50);
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf);
|
||||
bmp::mpfr_float a_actual(Buf);
|
||||
decn_to_str_complete(&BDecn);
|
||||
CAPTURE(Buf);
|
||||
bmp::mpfr_float b_actual(Buf);
|
||||
//calc result
|
||||
div_decn();
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // acc / b
|
||||
|
||||
//calculate actual result
|
||||
a_actual /= b_actual;
|
||||
if (decn_is_nan(&AccDecn)){
|
||||
//check that NaN result of division by 0
|
||||
CAPTURE(a_actual);
|
||||
CHECK(b_actual == 0);
|
||||
} else {
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
bmp::mpfr_float rel_diff = abs((a_actual - calculated) / a_actual);
|
||||
CHECK(rel_diff < 2e-17);
|
||||
}
|
||||
}
|
||||
|
||||
static void div_test(
|
||||
//input
|
||||
const char* a_str, int a_exp,
|
||||
const char* b_str, int b_exp
|
||||
)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
CAPTURE(b_str); CAPTURE(b_exp);
|
||||
//do division
|
||||
build_dec80(a_str, a_exp);
|
||||
build_decn_at(&BDecn, b_str, b_exp);
|
||||
div_test();
|
||||
}
|
||||
|
||||
TEST_CASE("division"){
|
||||
div_test(
|
||||
"1", 0,
|
||||
"0", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"3.14", 60,
|
||||
"-1.5", -2
|
||||
);
|
||||
|
||||
div_test(
|
||||
"4", 0,
|
||||
"4", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"1", 0,
|
||||
"3", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"500", 0,
|
||||
"99", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"500", 0,
|
||||
"2", 0
|
||||
);
|
||||
|
||||
div_test(
|
||||
"3", 0,
|
||||
"25", -15
|
||||
);
|
||||
|
||||
div_test(
|
||||
"0.02", 0,
|
||||
"0.03", 0
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE("division random"){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0, 99);
|
||||
std::uniform_int_distribution<int> sign_distrib(0,1);
|
||||
for (int j = 0; j < NUM_RAND_TESTS; j++){
|
||||
AccDecn.lsu[0] = distrib(gen);
|
||||
BDecn.lsu[0] = distrib(gen);
|
||||
for (int i = 1; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
BDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
set_exponent(&AccDecn, distrib(gen), sign_distrib(gen));
|
||||
set_exponent(&BDecn, distrib(gen), sign_distrib(gen));
|
||||
div_test();
|
||||
}
|
||||
}
|
||||
|
||||
static void sqrt_test(){
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf);
|
||||
//calculate result
|
||||
sqrt_decn();
|
||||
//build mpfr float
|
||||
bmp::mpfr_float::default_precision(50);
|
||||
bmp::mpfr_float x_actual(Buf);
|
||||
//print calc result
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf);
|
||||
//calculate actual result
|
||||
CAPTURE(x_actual);
|
||||
if (decn_is_nan(&AccDecn)){
|
||||
//check that NaN is from result of sqrt(-)
|
||||
CHECK(x_actual <= 0);
|
||||
} else if (decn_is_zero(&AccDecn)){
|
||||
//check actual is also 0
|
||||
CHECK(x_actual == 0);
|
||||
} else {
|
||||
x_actual = sqrt(x_actual);
|
||||
CAPTURE(x_actual);
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
bmp::mpfr_float rel_diff = abs((x_actual - calculated) / x_actual);
|
||||
CHECK(rel_diff < 2e-17);
|
||||
}
|
||||
}
|
||||
|
||||
static void sqrt_test(const char* x_str, int x_exp)
|
||||
{
|
||||
CAPTURE(x_str); CAPTURE(x_exp);
|
||||
build_dec80(x_str, x_exp);
|
||||
sqrt_test();
|
||||
}
|
||||
|
||||
TEST_CASE("sqrt"){
|
||||
sqrt_test("0", 0);
|
||||
sqrt_test("2", 0);
|
||||
sqrt_test("-1", 0);
|
||||
sqrt_test("0.155", 0);
|
||||
sqrt_test("10", 0);
|
||||
sqrt_test("1.1", 10);
|
||||
sqrt_test("2.02", -10);
|
||||
sqrt_test("2.02", 0);
|
||||
sqrt_test("1.5", 0);
|
||||
sqrt_test("9", 99);
|
||||
sqrt_test("123", 12345);
|
||||
}
|
||||
|
||||
TEST_CASE("sqrt random"){
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<int> distribution(0,99);
|
||||
std::uniform_int_distribution<int> exp_distrib(-99,99);
|
||||
std::uniform_int_distribution<int> sign_distrib(0,1);
|
||||
for (int j = 0; j < NUM_RAND_TESTS; j++){
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distribution(generator);
|
||||
}
|
||||
int sign = sign_distrib(generator);
|
||||
set_exponent(&AccDecn, exp_distrib(generator), sign);
|
||||
sqrt_test();
|
||||
}
|
||||
}
|
490
src/decn/decn_tests_transcendental.cpp
Normal file
490
src/decn/decn_tests_transcendental.cpp
Normal file
@ -0,0 +1,490 @@
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
* decn_tests_transcendental.cpp
|
||||
*
|
||||
* Unit tests using https://github.com/catchorg/Catch2
|
||||
*
|
||||
* separate out transcendental function tests
|
||||
*
|
||||
* Created on: Oct 26, 2020
|
||||
*/
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <boost/multiprecision/mpfr.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include "decn.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#include "decn_tests.h"
|
||||
|
||||
|
||||
namespace bmp = boost::multiprecision;
|
||||
using Catch::Matchers::Equals;
|
||||
|
||||
|
||||
static void log_test_(bool base10, double epsilon){
|
||||
bmp::mpfr_float::default_precision(50);
|
||||
CAPTURE(base10);
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf);
|
||||
//build mpfr float
|
||||
bmp::mpfr_float x_actual(Buf);
|
||||
//calculate result
|
||||
if (base10){
|
||||
log10_decn();
|
||||
} else {
|
||||
ln_decn();
|
||||
}
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // log(x)
|
||||
|
||||
//calculate actual result
|
||||
CAPTURE(x_actual);
|
||||
if (decn_is_nan(&AccDecn)){
|
||||
//check that NaN is from result of log(-)
|
||||
CHECK(x_actual <= 0);
|
||||
} else {
|
||||
if (base10){
|
||||
x_actual = log10(x_actual);
|
||||
} else {
|
||||
x_actual = log(x_actual);
|
||||
}
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
CAPTURE(calculated);
|
||||
bmp::mpfr_float rel_diff = abs((x_actual - calculated) / x_actual);
|
||||
CHECK(rel_diff < epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
static void log_test(bool base10=false){
|
||||
//check if near 1.0
|
||||
remove_leading_zeros(&AccDecn);
|
||||
double lsu0 = AccDecn.lsu[0];
|
||||
int exp = get_exponent(&AccDecn);
|
||||
if (exp == -1){
|
||||
lsu0 /= (double) 10;
|
||||
lsu0 += (double) AccDecn.lsu[1] / (10*100);
|
||||
lsu0 += (double) AccDecn.lsu[2] / (10*100*100);
|
||||
lsu0 += (double) AccDecn.lsu[3] / (10*100*100*100);
|
||||
} else if (exp == 0){
|
||||
lsu0 += (double) AccDecn.lsu[1] / 100;
|
||||
lsu0 += (double) AccDecn.lsu[2] / (100*100);
|
||||
lsu0 += (double) AccDecn.lsu[3] / (100*100*100);
|
||||
}
|
||||
CAPTURE((int) AccDecn.lsu[0]); CAPTURE((int) AccDecn.lsu[1]);
|
||||
CAPTURE(exp);
|
||||
CAPTURE(lsu0);
|
||||
if (exp == 0 || exp == -1){
|
||||
//check if near 1.0
|
||||
if (lsu0 >= 7 && lsu0 < 8){
|
||||
log_test_(base10, 7.5e-16);
|
||||
} else if (lsu0 >= 8 && lsu0 < 9){
|
||||
log_test_(base10, 1.5e-15);
|
||||
} else if (lsu0 >= 9 && lsu0 < 9.6){
|
||||
log_test_(base10, 1.0e-14);
|
||||
} else if (lsu0 >= 9.6 && lsu0 < 9.9){
|
||||
log_test_(base10, 4.1e-13);
|
||||
} else if (lsu0 >= 9.9 && lsu0 < 9.999){
|
||||
log_test_(base10, 1.5e-11);
|
||||
} else if (lsu0 >= 9.999 && lsu0 < 9.99999){
|
||||
log_test_(base10, 6.0e-10);
|
||||
} else if (lsu0 >= 9.99999 && lsu0 < 9.9999999){
|
||||
log_test_(base10, 3.0e-9);
|
||||
} else if (lsu0 >= 9.9999999 && lsu0 < 10.0){
|
||||
log_test_(base10, 1.3e-7);
|
||||
} else if (lsu0 >= 10.0 && lsu0 < 10.00001){
|
||||
log_test_(base10, 6.0e-10);
|
||||
} else if (lsu0 >= 10.00001 && lsu0 < 10.001){
|
||||
log_test_(base10, 6.0e-11);
|
||||
} else if (lsu0 >= 10.001 && lsu0 < 10.1){
|
||||
log_test_(base10, 1.5e-12);
|
||||
} else if (lsu0 >= 10.1 && lsu0 < 11){
|
||||
log_test_(base10, 1.6e-14);
|
||||
} else if (lsu0 >= 11 && lsu0 < 13){
|
||||
log_test_(base10, 2.0e-15);
|
||||
} else {
|
||||
log_test_(base10, 6.5e-16);
|
||||
}
|
||||
} else {
|
||||
log_test_(base10, 2e-16);
|
||||
}
|
||||
}
|
||||
|
||||
static void log_test(
|
||||
//input
|
||||
const char* x_str, int x_exp,
|
||||
bool base10=false
|
||||
)
|
||||
{
|
||||
CAPTURE(x_str); CAPTURE(x_exp);
|
||||
CAPTURE(base10);
|
||||
build_dec80(x_str, x_exp);
|
||||
log_test(base10);
|
||||
}
|
||||
|
||||
TEST_CASE("log"){
|
||||
log_test("0", 0);
|
||||
log_test("-1", 0);
|
||||
log_test("0.155", 0);
|
||||
log_test("10", 0);
|
||||
log_test("1.1", 10);
|
||||
log_test("2.02", -10);
|
||||
log_test("2.02", 0);
|
||||
log_test("1.5", 0, true);
|
||||
log_test("9", 99);
|
||||
log_test("123", 12345);
|
||||
}
|
||||
|
||||
TEST_CASE("log random"){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0,99);
|
||||
std::uniform_int_distribution<int> exp_distrib(-99,99);
|
||||
std::uniform_int_distribution<int> sign_distrib(0,1);
|
||||
for (int j = 0; j < NUM_RAND_TESTS; j++){
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
int exp = exp_distrib(gen);
|
||||
set_exponent(&AccDecn, exp, 0);
|
||||
int base10 = sign_distrib(gen);
|
||||
log_test(base10);
|
||||
}
|
||||
}
|
||||
|
||||
static void log_test_near1(int lsu0_low, int lsu0_high, int exp){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> lsu0_distrib(lsu0_low, lsu0_high);
|
||||
std::uniform_int_distribution<int> distrib(0,99);
|
||||
std::uniform_int_distribution<int> exp_distrib(-99,99);
|
||||
std::uniform_int_distribution<int> sign_distrib(0,1);
|
||||
for (int j = 0; j < NUM_RAND_TESTS; j++){
|
||||
AccDecn.lsu[0] = lsu0_distrib(gen);
|
||||
for (int i = 1; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
set_exponent(&AccDecn, exp, 0);
|
||||
int base10 = sign_distrib(gen);
|
||||
log_test(base10);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("log random 0 to 0.99..."){
|
||||
log_test_near1(0, 99, -1);
|
||||
}
|
||||
TEST_CASE("log random 0.8 to 0.99..."){
|
||||
log_test_near1(80, 99, -1);
|
||||
}
|
||||
TEST_CASE("log random 1.0 to 9.9"){
|
||||
log_test_near1(10, 99, 0);
|
||||
}
|
||||
TEST_CASE("log random 1.0 to 2.0"){
|
||||
log_test_near1(10, 20, 0);
|
||||
}
|
||||
|
||||
static void exp_test_(bool base10, double epsilon){
|
||||
bmp::mpfr_float::default_precision(50);
|
||||
CAPTURE(base10);
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); //x
|
||||
CAPTURE(AccDecn.exponent);
|
||||
//build mpfr float
|
||||
bmp::mpfr_float x_actual(Buf);
|
||||
//calculate result
|
||||
if (base10){
|
||||
exp10_decn();
|
||||
} else {
|
||||
exp_decn();
|
||||
}
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // exp(x)
|
||||
|
||||
//calculate actual result
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
if (base10){
|
||||
x_actual *= log(10);
|
||||
}
|
||||
x_actual = exp(x_actual);
|
||||
CAPTURE(x_actual);
|
||||
bmp::mpfr_float rel_diff = abs((x_actual - calculated) / x_actual);
|
||||
CHECK(rel_diff < epsilon);
|
||||
}
|
||||
|
||||
static void exp_test(bool base10=false){
|
||||
double x;
|
||||
int exp = get_exponent(&AccDecn);
|
||||
if (exp == 1){
|
||||
x = AccDecn.lsu[0];
|
||||
x += (double) AccDecn.lsu[1] / 100;
|
||||
} else if (exp == 2){
|
||||
x = (double) AccDecn.lsu[0] * 10;
|
||||
x += (double) AccDecn.lsu[1] / 10;
|
||||
}
|
||||
CAPTURE((int) AccDecn.lsu[0]); CAPTURE((int) AccDecn.lsu[1]);
|
||||
CAPTURE(exp);
|
||||
CAPTURE(x);
|
||||
double epsilon;
|
||||
if (exp == 1 || exp == 2){
|
||||
if (x > 230){
|
||||
epsilon = 8e-15;
|
||||
} else if (x > 210){
|
||||
epsilon = 6e-15;
|
||||
} else if (x > 180){
|
||||
epsilon = 5e-15;
|
||||
} else if (x > 150){
|
||||
epsilon = 4e-15;
|
||||
} else if (x > 125){
|
||||
epsilon = 3e-15;
|
||||
} else if (x > 100){
|
||||
epsilon = 2e-15;
|
||||
} else if (x > 65){
|
||||
epsilon = 1e-15;
|
||||
}
|
||||
} else {
|
||||
epsilon = 6e-16;
|
||||
}
|
||||
CAPTURE(base10);
|
||||
if (base10){
|
||||
epsilon *= 20;
|
||||
}
|
||||
exp_test_(base10, epsilon);
|
||||
}
|
||||
|
||||
static void exp_test(
|
||||
//input
|
||||
const char* x_str, int x_exp,
|
||||
bool base10=false
|
||||
)
|
||||
{
|
||||
CAPTURE(x_str); CAPTURE(x_exp);
|
||||
CAPTURE(base10);
|
||||
build_dec80(x_str, x_exp);
|
||||
exp_test(base10);
|
||||
}
|
||||
|
||||
static void exp10_test(const char* x_str, int x_exp){
|
||||
exp_test(x_str, x_exp, true);
|
||||
}
|
||||
|
||||
TEST_CASE("exp"){
|
||||
exp_test("4.4", 0);
|
||||
exp_test("0.155", 0);
|
||||
exp_test("9.999", 0);
|
||||
exp_test("10", 0);
|
||||
exp_test("10.001", 0);
|
||||
exp_test("2.3", 2);//, 6e-15);
|
||||
exp_test("2.02", -10);
|
||||
exp_test("2.02", 0);
|
||||
exp_test("1.5", 0);
|
||||
exp_test("99.999999", 0);
|
||||
exp_test("230.2", 0);//, 6e-15);
|
||||
exp_test("-230", 0);//, 6e-15);
|
||||
exp_test("294.69999999", 0);//, 8e-15);
|
||||
|
||||
//do not operate on NaN
|
||||
set_dec80_NaN(&AccDecn);
|
||||
exp_decn();
|
||||
CHECK(decn_is_nan(&AccDecn)); //still NaN
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("exp10"){
|
||||
exp10_test("4.4", 0);
|
||||
exp10_test("0.155", 0);
|
||||
exp10_test("9.999", 0);
|
||||
exp10_test("10", 0);
|
||||
exp10_test("10.001", 0);
|
||||
exp10_test("2.02", -10);
|
||||
exp10_test("2.02", 0);
|
||||
exp10_test("1.5", 0);
|
||||
exp10_test("127", 0);//, 3e-14);
|
||||
exp10_test("99.999999", 0);//, 2e-14);
|
||||
}
|
||||
|
||||
static void test_exp_random(int exp_distrib_low){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0, 99);
|
||||
std::uniform_int_distribution<int> lsu0_high_distrib(0, 23);
|
||||
std::uniform_int_distribution<int> exp_distrib(exp_distrib_low, 2);
|
||||
std::uniform_int_distribution<int> sign_distrib(0, 1);
|
||||
for (int j = 0; j < NUM_RAND_TESTS; j++){
|
||||
int exp = exp_distrib(gen);
|
||||
int sign = sign_distrib(gen);
|
||||
if (exp == 2) {
|
||||
//limit x to approximately +/- 230
|
||||
AccDecn.lsu[0] = lsu0_high_distrib(gen);
|
||||
} else {
|
||||
AccDecn.lsu[0] = distrib(gen);
|
||||
}
|
||||
for (int i = 1; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
set_exponent(&AccDecn, exp, sign);
|
||||
exp_test();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("exp random"){
|
||||
test_exp_random(-99);
|
||||
}
|
||||
TEST_CASE("exp large random"){
|
||||
test_exp_random(1);
|
||||
}
|
||||
|
||||
static void pow_test(){ // a^b
|
||||
bmp::mpf_float::default_precision(50);
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // a
|
||||
bmp::mpfr_float a_actual(Buf);
|
||||
decn_to_str_complete(&BDecn);
|
||||
CAPTURE(Buf); // b
|
||||
bmp::mpfr_float b_actual(Buf);
|
||||
//calculate result
|
||||
pow_decn();
|
||||
//calculate actual result
|
||||
bmp::mpfr_float res_actual(pow(a_actual, b_actual));
|
||||
//check overflow or underflow
|
||||
if (decn_is_nan(&AccDecn)){
|
||||
//check overflow or underflow
|
||||
if (b_actual > 0) {
|
||||
CHECK(log(res_actual) > 100);
|
||||
} else {
|
||||
CHECK(log(res_actual) < -100);
|
||||
}
|
||||
return;
|
||||
}
|
||||
//not over/underflow, get string and log calculated result
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf); // a^b
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
//check relative error
|
||||
double rel_tol = 4.5e-14;
|
||||
if (a_actual > 1.0 && a_actual < 1.0001){
|
||||
rel_tol = 1e-7;
|
||||
} else if (a_actual > 0.9 && a_actual < 2.0){
|
||||
rel_tol = 1.5e-10;
|
||||
} else if (log(res_actual) > 100){
|
||||
rel_tol = 1e-12;
|
||||
}
|
||||
CAPTURE(a_actual);
|
||||
CAPTURE(rel_tol);
|
||||
if (decn_is_zero(&AccDecn)) {
|
||||
bmp::mpfr_float diff = abs(res_actual - calculated);
|
||||
CHECK(diff < rel_tol);
|
||||
} else {
|
||||
bmp::mpfr_float rel_diff = abs((res_actual - calculated)/res_actual);
|
||||
CHECK(rel_diff < rel_tol);
|
||||
}
|
||||
}
|
||||
|
||||
static void pow_test(
|
||||
//input
|
||||
const char* a_str, int a_exp,
|
||||
const char* b_str, int b_exp
|
||||
)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
CAPTURE(b_str); CAPTURE(b_exp);
|
||||
|
||||
//compute power
|
||||
build_decn_at(&BDecn, b_str, b_exp);
|
||||
build_dec80(a_str, a_exp);
|
||||
pow_test();
|
||||
}
|
||||
|
||||
TEST_CASE("power"){
|
||||
pow_test(
|
||||
"3.14", 60,
|
||||
"-1.5", -2
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"3", 0,
|
||||
"201", 0
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"5", 0,
|
||||
"0", 0
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"5", 0,
|
||||
"0", 2
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"0", 0,
|
||||
"5", 0
|
||||
);
|
||||
|
||||
pow_test(
|
||||
"0", 0,
|
||||
"0", 0
|
||||
);
|
||||
}
|
||||
|
||||
static void power_test(int lsu0_low, int lsu0_high, int exp_low=-99, int exp_high=99){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> lsu0_distrib(lsu0_low, lsu0_high);
|
||||
std::uniform_int_distribution<int> distrib(0, 99);
|
||||
std::uniform_int_distribution<int> exp_distrib(exp_low, exp_high);
|
||||
std::uniform_int_distribution<int> sign_distrib(0,1);
|
||||
for (int j = 0; j < NUM_RAND_TESTS; j++){
|
||||
AccDecn.lsu[0] = lsu0_distrib(gen);
|
||||
for (int i = 1; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
BDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
set_exponent(&AccDecn, exp_distrib(gen), 0);
|
||||
//generate exponent for b to minimize chance of a^b overflowing:
|
||||
// a^b <= 1e100
|
||||
// b*log(a) <= log(1e100) = 100
|
||||
// b <= 100/log(a)
|
||||
// b_exponent <= log(100/log(a)) = log(100) - log(log(a))
|
||||
// b_exponent <= 2 - log(log(a))
|
||||
decn_to_str_complete(&AccDecn);
|
||||
bmp::mpfr_float acc(Buf);
|
||||
acc = 2.0 - log(log(acc));
|
||||
double b_exponent_high_flt = acc.convert_to<double>();
|
||||
int b_exponent_high = b_exponent_high_flt;
|
||||
int b_exponent_low = -99;
|
||||
//ensure b_exponent high in range
|
||||
if (b_exponent_high > 99){
|
||||
b_exponent_high = 99;
|
||||
} else if (b_exponent_high < b_exponent_low){
|
||||
b_exponent_high = b_exponent_low;
|
||||
}
|
||||
CAPTURE(b_exponent_low);
|
||||
CAPTURE(b_exponent_high);
|
||||
std::uniform_int_distribution<int> b_exp_distrib(b_exponent_low, b_exponent_high);
|
||||
int b_exponent = b_exp_distrib(gen);
|
||||
CAPTURE(b_exponent);
|
||||
int b_neg = sign_distrib(gen);
|
||||
set_exponent(&BDecn, b_exponent, b_neg);
|
||||
pow_test();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("power random"){
|
||||
power_test(0, 99);
|
||||
}
|
||||
TEST_CASE("power random 0.9 to 0.99..."){
|
||||
power_test(90, 99, -1, -1);
|
||||
}
|
||||
TEST_CASE("power random 1.0 to 2.0..."){
|
||||
power_test(10, 20, 0, 0);
|
||||
}
|
562
src/decn/decn_tests_trig.cpp
Normal file
562
src/decn/decn_tests_trig.cpp
Normal file
@ -0,0 +1,562 @@
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <boost/multiprecision/mpfr.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include "decn.h"
|
||||
|
||||
#include "decn_tests.h"
|
||||
|
||||
namespace bmp = boost::multiprecision;
|
||||
using Catch::Matchers::Equals;
|
||||
|
||||
static const bmp::mpfr_float mPI = boost::math::constants::pi<bmp::mpfr_float>();
|
||||
|
||||
|
||||
static void trig_test(void (*operation)(void), bmp::mpfr_float (*mpfr_operation)(bmp::mpfr_float x),
|
||||
double rtol, double atol)
|
||||
{
|
||||
//build mpfr float
|
||||
bmp::mpfr_float::default_precision(50);
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf);
|
||||
bmp::mpfr_float a_actual(Buf);
|
||||
//calculate
|
||||
operation();
|
||||
decn_to_str_complete(&AccDecn);
|
||||
CAPTURE(Buf);
|
||||
//calculate actual
|
||||
a_actual = mpfr_operation(a_actual);
|
||||
CAPTURE(a_actual);
|
||||
|
||||
bmp::mpfr_float calculated(Buf);
|
||||
if (rtol >= 0) {
|
||||
bmp::mpfr_float rel_diff = abs((a_actual - calculated) / a_actual);
|
||||
CHECK(rel_diff < rtol);
|
||||
} else {
|
||||
bmp::mpfr_float diff = abs(a_actual - calculated);
|
||||
CHECK(diff < atol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sin_test(double rtol=6e-3, double atol=1e-3)
|
||||
{
|
||||
CAPTURE("sin test");
|
||||
trig_test(sin_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return sin(x * mPI / 180);}, rtol, atol);
|
||||
}
|
||||
|
||||
static void sin_test(const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
build_dec80(a_str, a_exp);
|
||||
sin_test(rtol, atol);
|
||||
}
|
||||
|
||||
|
||||
static void cos_test(double rtol=6e-3, double atol=1e-3)
|
||||
{
|
||||
CAPTURE("cos test");
|
||||
trig_test(cos_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return cos(x * mPI / 180);}, rtol, atol);
|
||||
}
|
||||
|
||||
static void cos_test(const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
build_dec80(a_str, a_exp);
|
||||
cos_test(rtol, atol);
|
||||
}
|
||||
|
||||
|
||||
static void tan_test(double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
trig_test(tan_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return tan(x * mPI / 180);}, rtol, atol);
|
||||
}
|
||||
|
||||
static void tan_test(const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
build_dec80(a_str, a_exp);
|
||||
tan_test(rtol, atol);
|
||||
}
|
||||
|
||||
|
||||
static void atan_test(double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
trig_test(arctan_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return atan(x)*180/mPI;}, rtol, atol);
|
||||
}
|
||||
|
||||
static void atan_test(const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
build_dec80(a_str, a_exp);
|
||||
atan_test(rtol, atol);
|
||||
}
|
||||
|
||||
|
||||
static void asin_test(double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
trig_test(arcsin_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return asin(x)*180/mPI;}, rtol, atol);
|
||||
}
|
||||
|
||||
static void asin_test(const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
build_dec80(a_str, a_exp);
|
||||
asin_test(rtol, atol);
|
||||
}
|
||||
|
||||
|
||||
static void acos_test(double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
trig_test(arccos_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return acos(x)*180/mPI;}, rtol, atol);
|
||||
}
|
||||
|
||||
static void acos_test(const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
|
||||
{
|
||||
CAPTURE(a_str); CAPTURE(a_exp);
|
||||
build_dec80(a_str, a_exp);
|
||||
acos_test(rtol, atol);
|
||||
}
|
||||
|
||||
// const char * const pi = "3.141592653589793239";
|
||||
// const char * const pi_threequarters = "2.356194490192344929";
|
||||
// const char * const pi_halved = "1.570796326794896619";
|
||||
// const char * const pi_quarter = ".7853981633974483096";
|
||||
|
||||
|
||||
TEST_CASE("sin") {
|
||||
sin_test("0.1", 0, 0.2);
|
||||
sin_test("0.0", 0, -1);
|
||||
sin_test("1.5", 0, 0.02);
|
||||
sin_test("2.0", 0, 0.02);
|
||||
sin_test("2.5", 0, 0.02);
|
||||
sin_test("3.0", 0, 0.02);
|
||||
sin_test("10", 0);
|
||||
sin_test("20", 0);
|
||||
sin_test("30", 0);
|
||||
sin_test("40", 0);
|
||||
sin_test("80", 0);
|
||||
sin_test("120", 0);
|
||||
sin_test("160", 0);
|
||||
sin_test("200", 0);
|
||||
sin_test("240", 0);
|
||||
sin_test("280", 0);
|
||||
sin_test("320", 0);
|
||||
sin_test("359", 0, 0.02);
|
||||
sin_test("360", 0, -1, 0.001);
|
||||
sin_test("361", 0, 0.02);
|
||||
sin_test("400", 0);
|
||||
// sin_test(pi, 0, -1);
|
||||
// sin_test(pi_quarter, 0);
|
||||
// sin_test(pi_halved, 0);
|
||||
// sin_test(pi_threequarters, 0);
|
||||
sin_test("180.0", 0, -1);
|
||||
sin_test("45.0", 0);
|
||||
sin_test("90.0", 0);
|
||||
sin_test("135.0", 0);
|
||||
sin_test("1000.0", 0);
|
||||
sin_test("-0.5", 0, 0.2);
|
||||
sin_test("-1.5", 0, 0.02);
|
||||
sin_test("-2.0", 0, 0.02);
|
||||
sin_test("-2.5", 0, 0.02);
|
||||
sin_test("-3.0", 0, 0.02);
|
||||
sin_test("-9.0", 0);
|
||||
sin_test("-18.0", 0);
|
||||
sin_test("-27.0", 0);
|
||||
sin_test("-1000.0", 0);
|
||||
sin_test("-30", 0);
|
||||
sin_test("-40", 0);
|
||||
sin_test("-80", 0);
|
||||
sin_test("-120", 0);
|
||||
sin_test("-160", 0);
|
||||
sin_test("-200", 0);
|
||||
sin_test("-240", 0);
|
||||
sin_test("-280", 0);
|
||||
sin_test("-320", 0);
|
||||
sin_test("-360", 0, -1, 0.001);
|
||||
sin_test("-400", 0);
|
||||
}
|
||||
|
||||
TEST_CASE("cos") {
|
||||
cos_test("0.1", 0, 0.2);
|
||||
cos_test("0.0", 0, -1);
|
||||
cos_test("1.5", 0, 0.02);
|
||||
cos_test("2.0", 0, 0.02);
|
||||
cos_test("2.5", 0, 0.02);
|
||||
cos_test("3.0", 0, 0.02);
|
||||
cos_test("10", 0);
|
||||
cos_test("20", 0);
|
||||
cos_test("30", 0);
|
||||
cos_test("40", 0);
|
||||
cos_test("80", 0);
|
||||
cos_test("120", 0);
|
||||
cos_test("160", 0);
|
||||
cos_test("200", 0);
|
||||
cos_test("240", 0);
|
||||
cos_test("280", 0, 0.006);
|
||||
cos_test("320", 0);
|
||||
cos_test("359", 0, 0.02);
|
||||
cos_test("360", 0, -1, 0.001);
|
||||
cos_test("361", 0, 0.02);
|
||||
cos_test("400", 0);
|
||||
// cos_test(pi, 0, -1);
|
||||
// cos_test(pi_quarter, 0);
|
||||
// cos_test(pi_halved, 0);
|
||||
// cos_test(pi_threequarters, 0);
|
||||
cos_test("180.0", 0, -1);
|
||||
cos_test("45.0", 0);
|
||||
cos_test("90.0", 0, -1, 0.001);
|
||||
cos_test("135.0", 0);
|
||||
cos_test("1000.0", 0, 0.006);
|
||||
cos_test("-0.5", 0, 0.2);
|
||||
cos_test("-1.5", 0, 0.02);
|
||||
cos_test("-2.0", 0, 0.02);
|
||||
cos_test("-2.5", 0, 0.02);
|
||||
cos_test("-3.0", 0, 0.02);
|
||||
cos_test("-9.0", 0);
|
||||
cos_test("-18.0", 0);
|
||||
cos_test("-27.0", 0);
|
||||
cos_test("-1000.0", 0);
|
||||
cos_test("-30", 0);
|
||||
cos_test("-40", 0);
|
||||
cos_test("-80", 0, 0.006);
|
||||
cos_test("-120", 0);
|
||||
cos_test("-160", 0);
|
||||
cos_test("-200", 0);
|
||||
cos_test("-240", 0);
|
||||
cos_test("-280", 0);
|
||||
cos_test("-320", 0);
|
||||
cos_test("-360", 0, -1, 0.001);
|
||||
cos_test("-400", 0);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("tan") {
|
||||
tan_test("0.1", 0, 0.2);
|
||||
tan_test("0.0", 0, -1);
|
||||
tan_test("1.5", 0, 0.02);
|
||||
tan_test("2.0", 0, 0.02);
|
||||
tan_test("2.5", 0, 0.02);
|
||||
tan_test("3.0", 0, 0.02);
|
||||
tan_test("10", 0);
|
||||
tan_test("20", 0);
|
||||
tan_test("30", 0);
|
||||
tan_test("40", 0);
|
||||
tan_test("80", 0);
|
||||
tan_test("120", 0);
|
||||
tan_test("160", 0);
|
||||
tan_test("200", 0);
|
||||
tan_test("240", 0);
|
||||
tan_test("280", 0, 0.006);
|
||||
tan_test("320", 0);
|
||||
tan_test("359", 0, 0.02);
|
||||
tan_test("360", 0, -1, 0.001);
|
||||
tan_test("361", 0, 0.02);
|
||||
tan_test("400", 0);
|
||||
// tan_test(pi, 0, -1);
|
||||
// tan_test(pi_quarter, 0);
|
||||
// tan_test(pi_halved, 0);
|
||||
// tan_test(pi_threequarters, 0);
|
||||
tan_test("180.0", 0, -1);
|
||||
tan_test("45.0", 0);
|
||||
tan_test("90.0", 0, 2);
|
||||
tan_test("135.0", 0);
|
||||
tan_test("1000.0", 0, 0.006);
|
||||
tan_test("-0.5", 0, 0.2);
|
||||
tan_test("-1.5", 0, 0.02);
|
||||
tan_test("-2.0", 0, 0.02);
|
||||
tan_test("-2.5", 0, 0.02);
|
||||
tan_test("-3.0", 0, 0.02);
|
||||
tan_test("-9.0", 0);
|
||||
tan_test("-18.0", 0);
|
||||
tan_test("-27.0", 0);
|
||||
tan_test("-1000.0", 0);
|
||||
tan_test("-30", 0);
|
||||
tan_test("-40", 0);
|
||||
tan_test("-80", 0, 0.006);
|
||||
tan_test("-120", 0);
|
||||
tan_test("-160", 0);
|
||||
tan_test("-200", 0);
|
||||
tan_test("-240", 0);
|
||||
tan_test("-280", 0);
|
||||
tan_test("-320", 0);
|
||||
tan_test("-360", 0, -1, 0.001);
|
||||
tan_test("-400", 0);
|
||||
}
|
||||
|
||||
TEST_CASE("arctan") {
|
||||
atan_test("0.001", 0, -1, 0.06);
|
||||
atan_test("-0.001", 0, -1, 0.06);
|
||||
atan_test("0.7", 0);
|
||||
atan_test("-0.7", 0);
|
||||
atan_test("0.1", 0);
|
||||
atan_test("-0.1", 0);
|
||||
atan_test("1.0", 0);
|
||||
atan_test("-1.0", 0);
|
||||
atan_test("2.0", 0);
|
||||
atan_test("-2.0", 0);
|
||||
atan_test("3.0", 0);
|
||||
atan_test("-3.0", 0);
|
||||
atan_test("0", 0, -1, 0.06);
|
||||
}
|
||||
|
||||
TEST_CASE("arcsin") {
|
||||
asin_test("0.001", 0, -1, 0.06);
|
||||
asin_test("-0.001", 0, -1, 0.06);
|
||||
asin_test("0.7", 0);
|
||||
asin_test("-0.7", 0);
|
||||
asin_test("0.1", 0, 1e-2);
|
||||
asin_test("-0.1", 0, 1e-2);
|
||||
asin_test("0.9", 0);
|
||||
asin_test("-0.9", 0);
|
||||
}
|
||||
|
||||
TEST_CASE("arccos") {
|
||||
acos_test("0.001", 0);
|
||||
acos_test("-0.001", 0);
|
||||
acos_test("0.7", 0);
|
||||
acos_test("-0.7", 0);
|
||||
acos_test("0.1", 0);
|
||||
acos_test("-0.1", 0);
|
||||
acos_test("0.9", 0);
|
||||
acos_test("-0.9", 0);
|
||||
}
|
||||
|
||||
|
||||
static const int NUM_RAND_TRIG_TESTS = 4321; //trig tests are slow
|
||||
|
||||
TEST_CASE("sin random"){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0,99);
|
||||
std::uniform_int_distribution<int> exp_distrib(0, 2); //restrict range for now
|
||||
std::uniform_int_distribution<int> sign_distrib(0,1);
|
||||
for (int j = 0; j < NUM_RAND_TRIG_TESTS; j++){
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
int exp = exp_distrib(gen);
|
||||
int sign = sign_distrib(gen);
|
||||
set_exponent(&AccDecn, exp, sign);
|
||||
remove_leading_zeros(&AccDecn);
|
||||
int lsu0 = AccDecn.lsu[0];
|
||||
exp = get_exponent(&AccDecn);
|
||||
CAPTURE(lsu0);
|
||||
CAPTURE(exp);
|
||||
CAPTURE(sign);
|
||||
if (exp <= -1){
|
||||
//very small
|
||||
sin_test(4000);
|
||||
} else if (exp == 0 && lsu0 < 50){
|
||||
//small
|
||||
sin_test(0.4);
|
||||
} else if (exp == 2 && lsu0 >= 17 && lsu0 <= 19){
|
||||
//near 180
|
||||
sin_test(3);
|
||||
} else if (exp == 2 && lsu0 >= 35 && lsu0 <= 36){
|
||||
//near 360
|
||||
sin_test(12);
|
||||
} else if (exp == 2 && lsu0 > 50){
|
||||
//large
|
||||
sin_test(35);
|
||||
} else {
|
||||
sin_test(0.02);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("cos random"){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0,99);
|
||||
std::uniform_int_distribution<int> exp_distrib(0, 2); //restrict range for now
|
||||
std::uniform_int_distribution<int> sign_distrib(0,1);
|
||||
for (int j = 0; j < NUM_RAND_TRIG_TESTS; j++){
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
int exp = exp_distrib(gen);
|
||||
int sign = sign_distrib(gen);
|
||||
set_exponent(&AccDecn, exp, sign);
|
||||
remove_leading_zeros(&AccDecn);
|
||||
int lsu0 = AccDecn.lsu[0];
|
||||
exp = get_exponent(&AccDecn);
|
||||
CAPTURE(lsu0);
|
||||
CAPTURE(exp);
|
||||
CAPTURE(sign);
|
||||
if (exp == 1 && lsu0 >= 89 && lsu0 <= 90){
|
||||
//very near 90
|
||||
cos_test(500);
|
||||
} else if (exp == 1 && lsu0 >= 87 && lsu0 <= 92){
|
||||
//near 90
|
||||
cos_test(2);
|
||||
} else if (exp == 2 && lsu0 >= 26 && lsu0 <= 27){
|
||||
//near 270
|
||||
cos_test(500);
|
||||
} else if (exp == 2 && lsu0 >= 44){
|
||||
//large
|
||||
cos_test(20);
|
||||
} else {
|
||||
cos_test(0.02);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("tan random"){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0,99);
|
||||
std::uniform_int_distribution<int> exp_distrib(0, 2); //restrict range for now
|
||||
std::uniform_int_distribution<int> sign_distrib(0,1);
|
||||
for (int j = 0; j < NUM_RAND_TRIG_TESTS; j++){
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
int exp = exp_distrib(gen);
|
||||
int sign = sign_distrib(gen);
|
||||
set_exponent(&AccDecn, exp, sign);
|
||||
remove_leading_zeros(&AccDecn);
|
||||
int lsu0 = AccDecn.lsu[0];
|
||||
exp = get_exponent(&AccDecn);
|
||||
CAPTURE(lsu0);
|
||||
CAPTURE(exp);
|
||||
CAPTURE(sign);
|
||||
if (exp <= -3){
|
||||
//extremely small
|
||||
tan_test(5000);
|
||||
} if (exp <= -1){
|
||||
//very small
|
||||
tan_test(400);
|
||||
} else if (exp == 0 && lsu0 < 50){
|
||||
//small
|
||||
tan_test(1);
|
||||
} else if (exp == 1 && lsu0 >= 89 && lsu0 <= 90){
|
||||
//very near 90
|
||||
tan_test(5);
|
||||
} else if (exp == 1 && lsu0 >= 87 && lsu0 <= 92){
|
||||
//near 90
|
||||
tan_test(1);
|
||||
} else if (exp == 2 && lsu0 >= 17 && lsu0 <= 19){
|
||||
//near 180
|
||||
tan_test(3);
|
||||
} else if (exp == 2 && lsu0 >= 26 && lsu0 <= 27){
|
||||
//near 270
|
||||
tan_test(5);
|
||||
} else if (exp == 2 && lsu0 >= 35 && lsu0 <= 37){
|
||||
//near 360
|
||||
tan_test(20);
|
||||
} else if (exp == 2 && lsu0 >= 44){
|
||||
//large
|
||||
tan_test(50);
|
||||
} else {
|
||||
tan_test(0.02);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("atan random"){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0, 99);
|
||||
std::uniform_int_distribution<int> exp_distrib(-1, 0); //restrict range for now
|
||||
std::uniform_int_distribution<int> sign_distrib(0, 1);
|
||||
for (int j = 0; j < NUM_RAND_TRIG_TESTS; j++){
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
int exp = exp_distrib(gen);
|
||||
int sign = sign_distrib(gen);
|
||||
set_exponent(&AccDecn, exp, sign);
|
||||
remove_leading_zeros(&AccDecn);
|
||||
int lsu0 = AccDecn.lsu[0];
|
||||
exp = get_exponent(&AccDecn);
|
||||
CAPTURE(lsu0);
|
||||
CAPTURE(exp);
|
||||
CAPTURE(sign);
|
||||
if (exp <= -6){
|
||||
//extremely small
|
||||
atan_test(10000);
|
||||
} else if (exp < -1 || (exp == -1 && lsu0 == 0)){
|
||||
//very small
|
||||
atan_test(100);
|
||||
} else if ((exp == -1 && lsu0 < 10) || (exp == 0 && lsu0 == 0)){
|
||||
//small
|
||||
atan_test(3);
|
||||
} else {
|
||||
atan_test(0.02);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("asin random"){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0, 99);
|
||||
std::uniform_int_distribution<int> exp_distrib(-2, -1); //restrict range for now
|
||||
std::uniform_int_distribution<int> sign_distrib(0, 1);
|
||||
for (int j = 0; j < NUM_RAND_TRIG_TESTS; j++){
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
int exp = exp_distrib(gen);
|
||||
int sign = sign_distrib(gen);
|
||||
set_exponent(&AccDecn, exp, sign);
|
||||
remove_leading_zeros(&AccDecn);
|
||||
int lsu0 = AccDecn.lsu[0];
|
||||
exp = get_exponent(&AccDecn);
|
||||
CAPTURE(lsu0);
|
||||
CAPTURE(exp);
|
||||
CAPTURE(sign);
|
||||
if (exp <= -7) {
|
||||
//extremely small
|
||||
asin_test(50000);
|
||||
} else if (exp < -5) {
|
||||
//very very small
|
||||
asin_test(1000);
|
||||
} else if (exp < -1 || (exp == -1 && lsu0 == 0)){
|
||||
//very small
|
||||
asin_test(100);
|
||||
} else if ((exp == -1 && lsu0 < 10) || (exp == 0 && lsu0 == 0)){
|
||||
//small
|
||||
asin_test(0.5);
|
||||
} else {
|
||||
asin_test(0.02);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("acos random"){
|
||||
std::default_random_engine gen;
|
||||
std::uniform_int_distribution<int> distrib(0, 99);
|
||||
std::uniform_int_distribution<int> exp_distrib(-2, -1); //restrict range for now
|
||||
std::uniform_int_distribution<int> sign_distrib(0, 1);
|
||||
for (int j = 0; j < NUM_RAND_TRIG_TESTS; j++){
|
||||
for (int i = 0; i < DEC80_NUM_LSU; i++){
|
||||
AccDecn.lsu[i] = distrib(gen);
|
||||
}
|
||||
int exp = exp_distrib(gen);
|
||||
int sign = sign_distrib(gen);
|
||||
set_exponent(&AccDecn, exp, sign);
|
||||
remove_leading_zeros(&AccDecn);
|
||||
int lsu0 = AccDecn.lsu[0];
|
||||
exp = get_exponent(&AccDecn);
|
||||
CAPTURE(lsu0);
|
||||
CAPTURE(exp);
|
||||
CAPTURE(sign);
|
||||
if ((exp == -1 && lsu0 == 99)){
|
||||
//near 1
|
||||
acos_test(10);
|
||||
} else {
|
||||
acos_test(0.02);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
#include <boost/multiprecision/mpfr.hpp>
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
// #define DEBUG
|
||||
#define DEBUG
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -51,7 +51,7 @@ int main(void){
|
||||
|
||||
//loop through values to test
|
||||
#ifdef DEBUG
|
||||
mpfr_float x(0.1, CALC_PRECISION);
|
||||
mpfr_float x(2.0, CALC_PRECISION);
|
||||
{
|
||||
#else
|
||||
for (mpfr_float x(1e-99, CALC_PRECISION); x < 1e99; x *= 1.03){
|
||||
@ -87,7 +87,7 @@ int main(void){
|
||||
x_exp++;
|
||||
est_signif = -0.18 * x_signif + 2.5;
|
||||
} else { //even
|
||||
//keep x_exp as is and approximate estimate significand as
|
||||
//keep x_exp as is and approximate estimated significand as
|
||||
// -0.056*x_signif + 0.79
|
||||
est_signif = -0.056 * x_signif + 0.79;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
"""
|
||||
Created on Wed Dec 11 00:56:01 2019
|
||||
|
||||
Calculate constants used for "0x5F3759DF" reciprocal sqrt
|
||||
|
||||
@author: jeffrey
|
||||
"""
|
||||
|
||||
|
28
src/lcd.c
28
src/lcd.c
@ -117,7 +117,7 @@ static char readBusy() {
|
||||
}
|
||||
|
||||
static void wait_busy() {
|
||||
unsigned int i;
|
||||
uint8_t i;
|
||||
for (i = 0; i < 100; i++){
|
||||
if (!readBusy()){
|
||||
return;
|
||||
@ -129,7 +129,6 @@ static void wait_busy() {
|
||||
}
|
||||
|
||||
static void LCD_OutChar(unsigned char c) {
|
||||
unsigned char lower = (c & 0x0f);
|
||||
DISABLE_INTERRUPTS();
|
||||
wait_busy();
|
||||
//output upper 4 bits:
|
||||
@ -155,9 +154,15 @@ void LCD_Open(void) {
|
||||
//P2 entire port
|
||||
P2M1 = 0;
|
||||
P2M0 = 0xff;
|
||||
#ifdef STACK_DEBUG
|
||||
// P3_4 is special
|
||||
P3M1 &= ~(0xe0);
|
||||
P3M0 |= (0xe0);
|
||||
#else
|
||||
//P3 pins 7:4
|
||||
P3M1 &= ~(0xf0);
|
||||
P3M0 |= (0xf0);
|
||||
#endif
|
||||
|
||||
_delay_ms(30); // to allow LCD powerup
|
||||
outCsrBlindNibble(0x03); // (DL=1 8-bit mode)
|
||||
@ -195,6 +200,13 @@ void LCD_Open(void) {
|
||||
LCD_OutChar(0x10);
|
||||
LCD_OutChar(0x1c);
|
||||
}
|
||||
//program shift down sign
|
||||
for (i = 0; i < 5; i++){
|
||||
LCD_OutChar(0x0);
|
||||
}
|
||||
LCD_OutChar(0x1F);
|
||||
LCD_OutChar(0x0E);
|
||||
LCD_OutChar(0x04);
|
||||
|
||||
//clear display
|
||||
LCD_Clear();
|
||||
@ -279,3 +291,15 @@ void LCD_Clear() {
|
||||
col = 0;
|
||||
}
|
||||
|
||||
void TERMIO_PrintU8(uint8_t x) {
|
||||
uint8_t i;
|
||||
for (i = 2; i; i--) {
|
||||
const uint8_t upper_nibble = (x & 0xf0) >> 4;
|
||||
if (upper_nibble <= 9) {
|
||||
TERMIO_PutChar(upper_nibble + '0');
|
||||
} else {
|
||||
TERMIO_PutChar((upper_nibble - 0x0a) + 'A');
|
||||
}
|
||||
x <<= 4;
|
||||
}
|
||||
}
|
||||
|
@ -31,12 +31,14 @@ void LCD_GoTo(uint8_t row, uint8_t col);
|
||||
void LCD_OutString(__xdata const char* string, uint8_t max_chars);
|
||||
void LCD_OutString_Initial(__code const char* string);
|
||||
short TERMIO_PutChar(unsigned char letter);
|
||||
void TERMIO_PrintU8(uint8_t x);
|
||||
void LCD_OutNibble(uint8_t x);
|
||||
void LCD_ClearToEnd(uint8_t curr_row);
|
||||
|
||||
//CGRAM character address
|
||||
#define CGRAM_EXP 0
|
||||
#define CGRAM_EXP_NEG 1
|
||||
#define CGRAM_DOWN 2
|
||||
|
||||
#include "utils.h"
|
||||
#ifdef DESKTOP
|
||||
|
@ -131,6 +131,8 @@ short TERMIO_PutChar(unsigned char letter) {
|
||||
lcd_buf[lcd_row][lcd_col] = 'E';
|
||||
} else if (letter == CGRAM_EXP_NEG) {
|
||||
lcd_buf[lcd_row][lcd_col] = '-';
|
||||
} else if (letter == CGRAM_DOWN) {
|
||||
lcd_buf[lcd_row][lcd_col] = 'V';
|
||||
} else {
|
||||
lcd_buf[lcd_row][lcd_col] = letter;
|
||||
}
|
||||
|
31
src/main.c
31
src/main.c
@ -28,6 +28,7 @@
|
||||
#else
|
||||
#include "stc15.h"
|
||||
#endif
|
||||
#include "stack_debug.h"
|
||||
|
||||
#define FOSC 11583000
|
||||
|
||||
@ -139,7 +140,7 @@ static void latch_on(void)
|
||||
|
||||
__xdata char EntryBuf[MAX_CHARS_PER_LINE + 1];
|
||||
__xdata uint8_t ExpBuf[2];
|
||||
__code const char VER_STR[32+1] = "STC RPN Calculator v1.10";
|
||||
__code const char VER_STR[32+1] = "STC RPN Calculator v1.14";
|
||||
|
||||
|
||||
enum {
|
||||
@ -225,7 +226,9 @@ int main()
|
||||
LCD_Open();
|
||||
KeyInit();
|
||||
Timer0Init(); //for reading keyboard
|
||||
BACKLIGHT_ON(); //turn on led backlight
|
||||
backlight_on(); //turn on led backlight
|
||||
stack_debug_init();
|
||||
stack_debug(0xfe);
|
||||
|
||||
ExpBuf[0] = 0;
|
||||
ExpBuf[1] = 0;
|
||||
@ -304,7 +307,7 @@ int main()
|
||||
switch(KEY_MAP[I_Key]){
|
||||
//////////
|
||||
case '0': {
|
||||
if (IsShifted){
|
||||
if (IsShiftedUp || IsShiftedDown){
|
||||
//off
|
||||
TURN_OFF();
|
||||
} else {
|
||||
@ -340,7 +343,7 @@ int main()
|
||||
case '7': //fallthrough
|
||||
case '8': //fallthrough
|
||||
case '9': {
|
||||
if (IsShifted){
|
||||
if (IsShiftedUp || IsShiftedDown){
|
||||
finish_process_entry();
|
||||
} else if ( EnteringExp >= ENTERING_EXP){
|
||||
if ( Exp_i == 0){
|
||||
@ -365,7 +368,7 @@ int main()
|
||||
} break;
|
||||
//////////
|
||||
case '.': {
|
||||
if (IsShifted){
|
||||
if (IsShiftedUp || IsShiftedDown){
|
||||
//STO
|
||||
finish_process_entry();
|
||||
} else {
|
||||
@ -388,7 +391,7 @@ int main()
|
||||
} break;
|
||||
//////////
|
||||
case '=': {
|
||||
if (IsShifted){ //RCL
|
||||
if (IsShiftedUp || IsShiftedDown){ //RCL
|
||||
finish_process_entry();
|
||||
} else { //Enter
|
||||
//track stack lift
|
||||
@ -398,9 +401,10 @@ int main()
|
||||
} break;
|
||||
//////////
|
||||
case 'c': {
|
||||
if (IsShifted || is_entering_done()){
|
||||
if (IsShiftedUp || IsShiftedDown || is_entering_done()){
|
||||
//clear
|
||||
IsShifted = 0;
|
||||
IsShiftedUp = 0;
|
||||
IsShiftedDown = 0;
|
||||
NoLift = 1;
|
||||
entering_done();
|
||||
EnteringExp = ENTERING_DONE_CLEARED;
|
||||
@ -518,8 +522,15 @@ int main()
|
||||
LCD_ClearToEnd(1);
|
||||
|
||||
//print shifted status
|
||||
if (IsShifted){
|
||||
if (IsShiftedUp){
|
||||
TERMIO_PutChar('^');
|
||||
#if defined(STACK_DEBUG) && defined(SHOW_STACK)
|
||||
TERMIO_PutChar(' ');
|
||||
TERMIO_PrintU8(stack_max);
|
||||
TERMIO_PutChar(' ');
|
||||
#endif
|
||||
} else if (IsShiftedDown){
|
||||
TERMIO_PutChar(CGRAM_DOWN);
|
||||
}
|
||||
|
||||
#ifdef DESKTOP
|
||||
@ -529,7 +540,7 @@ int main()
|
||||
LcdAvailable.release();
|
||||
#endif
|
||||
//turn backlight back on
|
||||
BACKLIGHT_ON();
|
||||
backlight_on();
|
||||
} //while (1)
|
||||
}
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
98
src/stack_debug.c
Normal file
98
src/stack_debug.c
Normal file
@ -0,0 +1,98 @@
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <stdint.h>
|
||||
#include "stack_debug.h"
|
||||
|
||||
#if defined(STACK_DEBUG)
|
||||
|
||||
inline static void HIGH() {
|
||||
P3_4 = 1;
|
||||
}
|
||||
|
||||
inline static void LOW() {
|
||||
P3_4 = 1;
|
||||
}
|
||||
|
||||
void stack_debug_init() {
|
||||
P3M1 &= ~(0x10);
|
||||
P3M0 |= 0x10;
|
||||
LOW();
|
||||
stack_debug_write(0x55);
|
||||
stack_debug_write(0xAA);
|
||||
stack_debug_write(0x55);
|
||||
stack_debug_write(0xAA);
|
||||
stack_debug_write(0x80);
|
||||
stack_debug_write(0x10);
|
||||
stack_debug_write(0x08);
|
||||
stack_debug_write(0x01);
|
||||
}
|
||||
|
||||
/*
|
||||
for frequency of 12.000 MHz (12.005 adjusted) this gives a rate of 1'190'000 Baud
|
||||
negative polarity, MSB
|
||||
*/
|
||||
|
||||
void stack_debug_write(uint8_t value) __naked {
|
||||
value;
|
||||
__asm
|
||||
.macro HIGH
|
||||
setb _P3_4
|
||||
.endm
|
||||
|
||||
.macro LOW
|
||||
clr _P3_4
|
||||
.endm
|
||||
|
||||
mov dph,r0
|
||||
mov a,dpl
|
||||
mov r0,#8
|
||||
; START
|
||||
HIGH ; 1
|
||||
nop ; 1
|
||||
nop ; 1
|
||||
nop ; 1
|
||||
stack_debug_1$:
|
||||
rlc a ; 1
|
||||
jc stack_debug_2$ ; 3
|
||||
HIGH ; 1
|
||||
djnz r0,stack_debug_1$ ; 4
|
||||
sjmp stack_debug_3$ ; 3
|
||||
stack_debug_2$:
|
||||
LOW ; 1
|
||||
djnz r0,stack_debug_1$ ; 4
|
||||
sjmp stack_debug_3$ ; 3
|
||||
stack_debug_3$:
|
||||
nop ; 1
|
||||
; STOP
|
||||
LOW ; 1
|
||||
nop ; 1
|
||||
nop ; 1
|
||||
|
||||
mov r0,dph ; 3
|
||||
ret ; 4
|
||||
__endasm;
|
||||
}
|
||||
|
||||
#if defined(STACK_DEBUG) && defined(SHOW_STACK)
|
||||
__xdata uint8_t stack_max = 0x00;
|
||||
#endif
|
||||
|
||||
void stack_debug(uint8_t marker) {
|
||||
#ifdef SHOW_STACK
|
||||
if (SP > stack_max) stack_max = SP;
|
||||
#endif
|
||||
stack_debug_write(marker);
|
||||
stack_debug_write(SP);
|
||||
}
|
||||
#endif // defined(STACK_DEBUG)
|
58
src/stack_debug.h
Normal file
58
src/stack_debug.h
Normal file
@ -0,0 +1,58 @@
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef SRC_STACK_DEBUG_H_
|
||||
#define SRC_STACK_DEBUG_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(DESKTOP)
|
||||
#include "stc15.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// P3_4 is connected to the cathode and the only pin that is not toggled normally
|
||||
// unfortunately, the hardware uart cannot be mapped to TX = P3_4
|
||||
|
||||
#if defined(STACK_DEBUG)
|
||||
void stack_debug_init(void);
|
||||
void stack_debug(uint8_t marker);
|
||||
void stack_debug_write(uint8_t value) __naked;
|
||||
#else
|
||||
#define stack_debug_init()
|
||||
#define stack_debug(marker)
|
||||
#endif
|
||||
|
||||
#if defined(STACK_DEBUG) && defined(SHOW_STACK)
|
||||
extern __xdata uint8_t stack_max;
|
||||
#endif
|
||||
|
||||
#if defined(DESKTOP) || defined(STACK_DEBUG)
|
||||
#define backlight_on()
|
||||
#define backlight_off()
|
||||
#else
|
||||
inline void backlight_on(void) {
|
||||
P3_4 = 0;
|
||||
}
|
||||
inline void backlight_off(void) {
|
||||
P3_4 = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -29,7 +29,6 @@ void _delay_us(uint8_t us)
|
||||
(void) us;
|
||||
}
|
||||
#endif
|
||||
void backlight_off(void){ }
|
||||
#else //!DESKTOP
|
||||
void _delay_ms(uint8_t ms)
|
||||
{
|
||||
@ -69,10 +68,6 @@ void _delay_us(uint8_t us)
|
||||
}
|
||||
#endif
|
||||
|
||||
void backlight_off(void){
|
||||
P3_4 = 1;
|
||||
}
|
||||
|
||||
#endif //ifdef desktop
|
||||
|
||||
#ifdef DESKTOP
|
||||
|
@ -35,9 +35,6 @@ void _delay_us(uint8_t us);
|
||||
#define _delay_us(x) _delay_ms(1)
|
||||
#endif
|
||||
|
||||
void backlight_off(void);
|
||||
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
#define DESKTOP
|
||||
@ -58,11 +55,9 @@ char* u32str(uint32_t x, char* buf, uint8_t base);
|
||||
#define __at uint8_t*
|
||||
#define SDCC_ISR(isr, reg)
|
||||
#define __using(x)
|
||||
#define BACKLIGHT_ON()
|
||||
#define TURN_OFF()
|
||||
#else
|
||||
#define SDCC_ISR(isr, reg) __interrupt (isr) __using (reg)
|
||||
#define BACKLIGHT_ON() P3_4 = 0
|
||||
#define TURN_OFF() P3_2 = 0
|
||||
#endif
|
||||
|
||||
|
9
steps/build_calc.sh
Executable file
9
steps/build_calc.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
# build
|
||||
cd $SCRIPT_DIR/..
|
||||
make
|
9
steps/compose_build.sh
Executable file
9
steps/compose_build.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
# build
|
||||
cd $SCRIPT_DIR
|
||||
docker-compose build
|
21
steps/compose_run.sh
Executable file
21
steps/compose_run.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
# set GITHUBWORKSPACE if building locally
|
||||
if [[ -z "${GITHUB_WORKSPACE}" ]]; then
|
||||
export GITHUB_WORKSPACE="$SCRIPT_DIR/.."
|
||||
fi
|
||||
echo "GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}"
|
||||
|
||||
# build
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
# start shell
|
||||
docker-compose run build_tools bash
|
||||
else
|
||||
docker-compose run build_tools /code/steps/$1
|
||||
fi
|
29
steps/desktop_build_check.sh
Executable file
29
steps/desktop_build_check.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
# build
|
||||
cd $SCRIPT_DIR/..
|
||||
if [ "$1" == "--rebuild" ]; then
|
||||
rm -rf build_qt
|
||||
mkdir build_qt
|
||||
else
|
||||
mkdir -p build_qt
|
||||
fi
|
||||
cd build_qt
|
||||
cmake .. -GNinja
|
||||
ninja
|
||||
|
||||
# run tests
|
||||
ctest -j $(nproc)
|
||||
|
||||
# get coverage
|
||||
echo "Running lcov"
|
||||
lcov --capture --directory src/decn --output-file coverage.info
|
||||
lcov --remove coverage.info "/usr/*" --output-file coverage.info
|
||||
genhtml coverage.info --output-directory lcov
|
||||
echo "Running gcov"
|
||||
gcov -b src/decn/CMakeFiles/decn_cover.dir/decn.c.gcno
|
||||
|
10
steps/docker-compose.yml
Normal file
10
steps/docker-compose.yml
Normal file
@ -0,0 +1,10 @@
|
||||
version: '3.2'
|
||||
services:
|
||||
build_tools:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- type: bind
|
||||
source: $GITHUB_WORKSPACE
|
||||
target: /code
|
Loading…
Reference in New Issue
Block a user