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

Desired feature: ability to disable sign printing on floating point zeros. (custom formatting) #331

Closed
spacemoose opened this issue May 19, 2016 · 5 comments

Comments

@spacemoose
Copy link
Contributor

We recently experimented with using fmtlib to alleviate a performance problem we were having with boost::format. I'm quite impressed with the library, but I have a feature need that prevents me from using it as is.

We need the ability to NOT print a sign when a floating point representation is textually zero. For example you have a number which is zero, but because of floating point precision issues, it's represented in memory is -0.000001. When we print "0.00" we get an unwanted sign -- "-0.00". We were able to solve this for boost::format by creating a custom num_put facet, but that approach won't work for fmtlib.

We can patch the library to get it to behave the way we want, but I suppose the reasons why this is undesirable is obvious.

So -- would you be interested in a patch that adds this functionality? Obviously we would first have to discuss the interface for controlling such a feature. I have some thoughts regarding the ability to add custom formatters to fmtlib similar to std::locale's facet functionality, but perhaps you already have thoughts on this topic If you think this might be interesting, let's start a dialogue.

@vitaut
Copy link
Contributor

vitaut commented May 19, 2016

Thanks for the suggestion and your interest in the library.

You can achieve the desired behavior by providing a custom argument formatter, for example:

#include "fmt/format.h"

// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class CustomArgFormatter :
  public fmt::BasicArgFormatter<CustomArgFormatter, char>  {
  public:
  CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
                     fmt::FormatSpec &s, const char *fmt)
    : fmt::BasicArgFormatter<CustomArgFormatter, char>(f, s, fmt) {}

  void visit_double(double value) {
    if (round(value * pow(10, spec().precision())) == 0)
      value = 0;
    fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_double(value);
  }
};

std::string custom_format(const char *format_str, fmt::ArgList args) {
  fmt::MemoryWriter writer;
  // Pass custom argument formatter as a template arg to BasicFormatter.
  fmt::BasicFormatter<char, CustomArgFormatter> formatter(args, writer);
  formatter.format(format_str);
  return writer.str();
}
FMT_VARIADIC(std::string, custom_format, const char *)

int main() {
  custom_format("{:.2f}", -0.000001); // returns "0.00"
}

Will it work for you?

@vitaut
Copy link
Contributor

vitaut commented May 23, 2016

I'm closing the issue but feel free to ask if you have any questions about this.

@vitaut vitaut closed this as completed May 23, 2016
@spacemoose
Copy link
Contributor Author

Just tried a quick test -- this looks like exactly what I need. Thanks very much for your support, and the excellent library!

@spacemoose
Copy link
Contributor Author

How can I accomplish the same thing using the fmt::printf interface?

@vitaut
Copy link
Contributor

vitaut commented May 26, 2016

You can't do it right now with fmt::printf because PrintfFormatter, doesn't support argument formatters, but it's possible to extend it in the same way as BasicFormatter. Feel free to open an issue if you are interested in this functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants