Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add simplified implementation in subproject/simple #67

Merged
merged 17 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ if (DRAGONBOX_ENABLE_SUBPROJECT)
add_subdirectory("subproject/benchmark")
add_subdirectory("subproject/meta")
add_subdirectory("subproject/test")
add_subdirectory("subproject/simple")
endif()

# ---- MSVC Specifics ----
Expand Down
9 changes: 9 additions & 0 deletions subproject/simple/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
add_library(simple_dragonbox INTERFACE simple_dragonbox.h)
target_compile_features(simple_dragonbox INTERFACE cxx_std_17)

add_executable(simple_dragonbox_test simple_dragonbox_test.cpp)
target_link_libraries(simple_dragonbox_test PRIVATE
simple_dragonbox
dragonbox::common
ryu::ryu
)
117 changes: 117 additions & 0 deletions subproject/simple/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Simple Dragonbox

This is a simplified implementation of the algorithm, that closely follows the
one in `include/dragonbox/dragonbox.h`, but aims to be shorter overall, use less
C++ template indirection, and offer slightly less flexibility for the benefit of
simpliciy.

Primary sacrifices over the implementation in `include/dragonbox/dragonbox.h`:

- No support for `sign` policies (always uses `return_sign`)
- No support for `trailing_zeros` policies (always uses `remove`)
- No support for 128-bit compiler intrinsics (always uses portable
implementation)
- No support for fast digit-generation policy (always uses `compact`)
- Assumes the existence of `if constexpr` (C++17)
- Assumes `float` and `double` types are available and use IEEE-754
- Generally assumes a modern standard compiler environment and C standard
library

Note the `cache`, `binary_to_decimal_rounding`, and `decimal_to_binary_rounding`
policies are still supported.

## API

### Basic use

To convert to decimal (analog to `jkj::dragonbox::to_decimal`),

```cpp
float x;
auto d = simple_dragonbox::to_decimal(x);
(void) d.significand;
(void) d.exponent;
(void) d.sign;
```

To convert to string (analog to `jkj::dragonbox::to_chars`),

```cpp
float x;
char buf[simple_dragonbox::max_output_string_length<float> + 1];
simple_dragonbox::to_chars(x, buf);
std::cout << buf << std::endl;
```

In the examples above, `x` can be either a `float` or a `double`.

### Policies

`simple_dragonbox` supports the same style of policy interface as
`jkj::dragonbox`. For example,

```cpp
simple_dragonbox::to_decimal(3.14,
simple_dragonbox::policy::cache::compact,
simple_dragonbox::policy::binary_to_decimal_rounding::to_odd);
```

Supported policies include:

`simple_dragonbox::policy::decimal_to_binary_rounding`

- `::nearest_to_even`
- `::nearest_to_odd`
- `::nearest_toward_plus_infinity`
- `::nearest_toward_minus_infinity`
- `::nearest_toward_zero`
- `::nearest_away_from_zero`
- `::nearest_to_even_static_boundary`
- `::nearest_to_odd_static_boundary`
- `::nearest_toward_plus_infinity_static_boundary`
- `::nearest_toward_minus_infinity_static_boundary`
- `::toward_plus_infinity`
- `::toward_minus_infinity`
- `::toward_zero`
- `::away_from_zero`

`simple_dragonbox::policy::binary_to_decimal_rounding`

- `::to_even`
- `::to_odd`
- `::away_from_zero`
- `::toward_zero`
- `::do_not_care`

`simple_dragonbox::policy::cache`

- `::full`
- `::compact`

### Internal/direct API

Internally, `simple_dragonbox` uses a more explicit, direct interface to express
the various policies, via a class called `simple_dragonbox::impl`. The `impl`
class has four template parameters: `Float`, `BinaryRoundMode`,
`DecimalRoundMode`, and `CacheType`, which correspond to the floating point
type and three categories of policies above. These template parameters can be
specified explicitly to instantiate a particular variant of the algorithm. The
class has a single constructor that receives a value of type `Float` (e.g.
`float` or `double`), and has methods `to_decimal()` and `to_chars()` for
performing the desired conversions.

For example,

```cpp
using impl = simple_dragonbox::impl<double,
simple_dragonbox::binary_round_mode::toward_zero,
simple_dragonbox::decimal_round_mode::toward_zero,
simple_dragonbox::cache_type::compact>;

int main() {
char buf[32];
auto x = impl(3.14);
x.to_decimal(); // equivalent to `simple_dragonbox::to_decimal(3.14, policies...)`
x.to_chars(buf); // equivalent to `simple_dragonbox::to_chars(3.14, buf, policies...)`
}
```
Loading
Loading