Add tags

Add tags to the following comment
boost::math::gcd で既約分数のチェックは楽できました。 それ以外は普通?
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <iostream>
#include <vector>
#include <functional>
#include <cmath>
#include <iterator>
#include <string>
#include <stdexcept>

#include <boost/math/common_factor_rt.hpp>
#include <boost/lexical_cast.hpp>

class rational_t
{
  int n_, d_;
  double r_;

  public:
  rational_t(int numerator, int denominator)
    : n_(numerator), d_(denominator),
    r_(static_cast<double>(n_)/static_cast<double>(d_)) {}

  double real() const
  { return r_; }
  bool isnan() const
  { return std::isnan(r_); }

  int numerator() const
  { return n_; }
  int denominator() const
  { return d_; }
};
std::ostream&
operator<<(std::ostream& os, const rational_t& r)
{
  return (os << r.numerator() << "/" << r.denominator());
}

class compare_near_to
: public std::binary_function<bool, rational_t, rational_t>
{
  double g_;
  public:
  compare_near_to(double goal) : g_(goal) {}

  bool operator()(
      const rational_t& lhs,
      const rational_t& rhs
      )
  {
    return std::fabs(g_-lhs.real()) < std::fabs(g_-rhs.real());
  }
};

rational_t
find_rational(
    double  goal,
    int     denominator
    )
{
  double min_diff = goal;

  rational_t rat(0, denominator);
  for ( int n = 1; ; ++n ) {
    rational_t rat_(n, denominator);
    double diff = std::fabs(goal - rat_.real());

    if ( diff > min_diff ) break;

    min_diff = diff;
    rat = rat_;
  }
  if ( boost::math::gcd(rat.numerator(), rat.denominator()) != 1 )
    return rational_t(0,0); // causes real is NaN
  return rat;
}

int main(int c, char** v)
{
  if ( c != 2 ) {
    std::cout << v[0] << " <real number|rational number>\n";
    return 0;
  }
  double goal;
  try {
    std::string val(v[1]);
    std::string::size_type idx;
    if ( (idx = val.find("/")) != std::string::npos )
      goal = boost::lexical_cast<double>(val.substr(0,idx)) /
            boost::lexical_cast<double>(val.substr(idx+1,val.length()-(idx+1)));
    else
      goal = boost::lexical_cast<double>(v[1]);

    if ( goal <= 0.0 )
      throw std::runtime_error("input number must be positive");
  }
  catch (const std::exception& e) {
    std::cerr << e.what() << "\n";
    return -1;
  }

  std::vector<rational_t> rationals;
  for ( int i = 1; i < 10; ++i )
    rationals.push_back(find_rational(goal, i));

  rationals.erase(
      std::remove_if(
        rationals.begin(),
        rationals.end(),
        std::mem_fun_ref(&rational_t::isnan) ),
      rationals.end());
  std::sort(
      rationals.begin(),
      rationals.end(),
      compare_near_to(goal) );

  std::copy(
      rationals.begin(),
      rationals.end(),
      std::ostream_iterator<rational_t>(std::cout, ", ") );

  return 0;
}

Add tags

The input will be splited to tags with space.

Index

Feed

Other

Link

Pathtraq

loading...