Лучший способ представить часть в Java?

Вот еще одно решение (просто замените 'вставлено' на '' для пустой строки. Если вы используете числа, используйте np.nan):

pd.DataFrame(np.insert(df.values, 0, values=['inserted'], axis=0)).rename(columns ={0:'col1'})

    col1
    0   inserted
    1   how
    2   to
    3   have
    4   an
    5   empty
    6   first
    7   row

Вы можете указать, где (какую строку) вы хотите значение, которое нужно вставить в:

pd.DataFrame(np.insert(df.values, 5, values=['inserted'], axis=0)).rename(columns ={0:'col1'})
col1
0   how
1   to
2   have
3   an
4   empty
5   inserted
6   first
7   row
95
задан 20 revs, 5 users 86% 23 May 2017 в 12:34
поделиться

20 ответов

Это именно так происходит, что я записал класс BigFraction не слишком долго назад, для Euler проблемы Проекта . Это сохраняет числитель BigInteger и знаменатель, таким образом, это никогда не будет переполняться. Но это будет немного медленно для большого количества операций, которые Вы знаете, никогда не будет переполняться.. так или иначе используйте его, если Вы хотите его. Я умер для представления в выгодном цвете этого так или иначе.:)

Редактирование : Последняя и самая большая версия этого кода, включая модульные тесты теперь размещена на GitHub и также доступный через Знатока, Центрального . Я оставляю свой исходный код здесь так, чтобы этот ответ не был просто ссылкой...

<час>
import java.math.*;

/**
 * Arbitrary-precision fractions, utilizing BigIntegers for numerator and
 * denominator.  Fraction is always kept in lowest terms.  Fraction is
 * immutable, and guaranteed not to have a null numerator or denominator.
 * Denominator will always be positive (so sign is carried by numerator,
 * and a zero-denominator is impossible).
 */
public final class BigFraction extends Number implements Comparable<BigFraction>
{
  private static final long serialVersionUID = 1L; //because Number is Serializable
  private final BigInteger numerator;
  private final BigInteger denominator;

  public final static BigFraction ZERO = new BigFraction(BigInteger.ZERO, BigInteger.ONE, true);
  public final static BigFraction ONE = new BigFraction(BigInteger.ONE, BigInteger.ONE, true);

  /**
   * Constructs a BigFraction with given numerator and denominator.  Fraction
   * will be reduced to lowest terms.  If fraction is negative, negative sign will
   * be carried on numerator, regardless of how the values were passed in.
   */
  public BigFraction(BigInteger numerator, BigInteger denominator)
  {
    if(numerator == null)
      throw new IllegalArgumentException("Numerator is null");
    if(denominator == null)
      throw new IllegalArgumentException("Denominator is null");
    if(denominator.equals(BigInteger.ZERO))
      throw new ArithmeticException("Divide by zero.");

    //only numerator should be negative.
    if(denominator.signum() < 0)
    {
      numerator = numerator.negate();
      denominator = denominator.negate();
    }

    //create a reduced fraction
    BigInteger gcd = numerator.gcd(denominator);
    this.numerator = numerator.divide(gcd);
    this.denominator = denominator.divide(gcd);
  }

  /**
   * Constructs a BigFraction from a whole number.
   */
  public BigFraction(BigInteger numerator)
  {
    this(numerator, BigInteger.ONE, true);
  }

  public BigFraction(long numerator, long denominator)
  {
    this(BigInteger.valueOf(numerator), BigInteger.valueOf(denominator));
  }

  public BigFraction(long numerator)
  {
    this(BigInteger.valueOf(numerator), BigInteger.ONE, true);
  }

  /**
   * Constructs a BigFraction from a floating-point number.
   * 
   * Warning: round-off error in IEEE floating point numbers can result
   * in answers that are unexpected.  For example, 
   *     System.out.println(new BigFraction(1.1))
   * will print:
   *     2476979795053773/2251799813685248
   * 
   * This is because 1.1 cannot be expressed exactly in binary form.  The
   * given fraction is exactly equal to the internal representation of
   * the double-precision floating-point number.  (Which, for 1.1, is:
   * (-1)^0 * 2^0 * (1 + 0x199999999999aL / 0x10000000000000L).)
   * 
   * NOTE: In many cases, BigFraction(Double.toString(d)) may give a result
   * closer to what the user expects.
   */
  public BigFraction(double d)
  {
    if(Double.isInfinite(d))
      throw new IllegalArgumentException("double val is infinite");
    if(Double.isNaN(d))
      throw new IllegalArgumentException("double val is NaN");

    //special case - math below won't work right for 0.0 or -0.0
    if(d == 0)
    {
      numerator = BigInteger.ZERO;
      denominator = BigInteger.ONE;
      return;
    }

    final long bits = Double.doubleToLongBits(d);
    final int sign = (int)(bits >> 63) & 0x1;
    final int exponent = ((int)(bits >> 52) & 0x7ff) - 0x3ff;
    final long mantissa = bits & 0xfffffffffffffL;

    //number is (-1)^sign * 2^(exponent) * 1.mantissa
    BigInteger tmpNumerator = BigInteger.valueOf(sign==0 ? 1 : -1);
    BigInteger tmpDenominator = BigInteger.ONE;

    //use shortcut: 2^x == 1 << x.  if x is negative, shift the denominator
    if(exponent >= 0)
      tmpNumerator = tmpNumerator.multiply(BigInteger.ONE.shiftLeft(exponent));
    else
      tmpDenominator = tmpDenominator.multiply(BigInteger.ONE.shiftLeft(-exponent));

    //1.mantissa == 1 + mantissa/2^52 == (2^52 + mantissa)/2^52
    tmpDenominator = tmpDenominator.multiply(BigInteger.valueOf(0x10000000000000L));
    tmpNumerator = tmpNumerator.multiply(BigInteger.valueOf(0x10000000000000L + mantissa));

    BigInteger gcd = tmpNumerator.gcd(tmpDenominator);
    numerator = tmpNumerator.divide(gcd);
    denominator = tmpDenominator.divide(gcd);
  }

  /**
   * Constructs a BigFraction from two floating-point numbers.
   * 
   * Warning: round-off error in IEEE floating point numbers can result
   * in answers that are unexpected.  See BigFraction(double) for more
   * information.
   * 
   * NOTE: In many cases, BigFraction(Double.toString(numerator) + "/" + Double.toString(denominator))
   * may give a result closer to what the user expects.
   */
  public BigFraction(double numerator, double denominator)
  {
    if(denominator == 0)
      throw new ArithmeticException("Divide by zero.");

    BigFraction tmp = new BigFraction(numerator).divide(new BigFraction(denominator));
    this.numerator = tmp.numerator;
    this.denominator = tmp.denominator;
  }

  /**
   * Constructs a new BigFraction from the given BigDecimal object.
   */
  public BigFraction(BigDecimal d)
  {
    this(d.scale() < 0 ? d.unscaledValue().multiply(BigInteger.TEN.pow(-d.scale())) : d.unscaledValue(),
         d.scale() < 0 ? BigInteger.ONE                                             : BigInteger.TEN.pow(d.scale()));
  }

  public BigFraction(BigDecimal numerator, BigDecimal denominator)
  {
    if(denominator.equals(BigDecimal.ZERO))
      throw new ArithmeticException("Divide by zero.");

    BigFraction tmp = new BigFraction(numerator).divide(new BigFraction(denominator));
    this.numerator = tmp.numerator;
    this.denominator = tmp.denominator;
  }

  /**
   * Constructs a BigFraction from a String.  Expected format is numerator/denominator,
   * but /denominator part is optional.  Either numerator or denominator may be a floating-
   * point decimal number, which in the same format as a parameter to the
   * <code>BigDecimal(String)</code> constructor.
   * 
   * @throws NumberFormatException  if the string cannot be properly parsed.
   */
  public BigFraction(String s)
  {
    int slashPos = s.indexOf('/');
    if(slashPos < 0)
    {
      BigFraction res = new BigFraction(new BigDecimal(s));
      this.numerator = res.numerator;
      this.denominator = res.denominator;
    }
    else
    {
      BigDecimal num = new BigDecimal(s.substring(0, slashPos));
      BigDecimal den = new BigDecimal(s.substring(slashPos+1, s.length()));
      BigFraction res = new BigFraction(num, den);
      this.numerator = res.numerator;
      this.denominator = res.denominator;
    }
  }

  /**
   * Returns this + f.
   */
  public BigFraction add(BigFraction f)
  {
    if(f == null)
      throw new IllegalArgumentException("Null argument");

    //n1/d1 + n2/d2 = (n1*d2 + d1*n2)/(d1*d2) 
    return new BigFraction(numerator.multiply(f.denominator).add(denominator.multiply(f.numerator)),
                           denominator.multiply(f.denominator));
  }

  /**
   * Returns this + b.
   */
  public BigFraction add(BigInteger b)
  {
    if(b == null)
      throw new IllegalArgumentException("Null argument");

    //n1/d1 + n2 = (n1 + d1*n2)/d1
    return new BigFraction(numerator.add(denominator.multiply(b)),
                           denominator, true);
  }

  /**
   * Returns this + n.
   */
  public BigFraction add(long n)
  {
    return add(BigInteger.valueOf(n));
  }

  /**
   * Returns this - f.
   */
  public BigFraction subtract(BigFraction f)
  {
    if(f == null)
      throw new IllegalArgumentException("Null argument");

    return new BigFraction(numerator.multiply(f.denominator).subtract(denominator.multiply(f.numerator)),
                           denominator.multiply(f.denominator));
  }

  /**
   * Returns this - b.
   */
  public BigFraction subtract(BigInteger b)
  {
    if(b == null)
      throw new IllegalArgumentException("Null argument");

    return new BigFraction(numerator.subtract(denominator.multiply(b)),
                           denominator, true);
  }

  /**
   * Returns this - n.
   */
  public BigFraction subtract(long n)
  {
    return subtract(BigInteger.valueOf(n));
  }

  /**
   * Returns this * f.
   */
  public BigFraction multiply(BigFraction f)
  {
    if(f == null)
      throw new IllegalArgumentException("Null argument");

    return new BigFraction(numerator.multiply(f.numerator), denominator.multiply(f.denominator));
  }

  /**
   * Returns this * b.
   */
  public BigFraction multiply(BigInteger b)
  {
    if(b == null)
      throw new IllegalArgumentException("Null argument");

    return new BigFraction(numerator.multiply(b), denominator);
  }

  /**
   * Returns this * n.
   */
  public BigFraction multiply(long n)
  {
    return multiply(BigInteger.valueOf(n));
  }

  /**
   * Returns this / f.
   */
  public BigFraction divide(BigFraction f)
  {
    if(f == null)
      throw new IllegalArgumentException("Null argument");

    if(f.numerator.equals(BigInteger.ZERO))
      throw new ArithmeticException("Divide by zero");

    return new BigFraction(numerator.multiply(f.denominator), denominator.multiply(f.numerator));
  }

  /**
   * Returns this / b.
   */
  public BigFraction divide(BigInteger b)
  {
    if(b == null)
      throw new IllegalArgumentException("Null argument");

    if(b.equals(BigInteger.ZERO))
      throw new ArithmeticException("Divide by zero");

    return new BigFraction(numerator, denominator.multiply(b));
  }

  /**
   * Returns this / n.
   */
  public BigFraction divide(long n)
  {
    return divide(BigInteger.valueOf(n));
  }

  /**
   * Returns this^exponent.
   */
  public BigFraction pow(int exponent)
  {
    if(exponent == 0)
      return BigFraction.ONE;
    else if (exponent == 1)
      return this;
    else if (exponent < 0)
      return new BigFraction(denominator.pow(-exponent), numerator.pow(-exponent), true);
    else
      return new BigFraction(numerator.pow(exponent), denominator.pow(exponent), true);
  }

  /**
   * Returns 1/this.
   */
  public BigFraction reciprocal()
  {
    if(this.numerator.equals(BigInteger.ZERO))
      throw new ArithmeticException("Divide by zero");

    return new BigFraction(denominator, numerator, true);
  }

  /**
   * Returns the complement of this fraction, which is equal to 1 - this.
   * Useful for probabilities/statistics.

   */
  public BigFraction complement()
  {
    return new BigFraction(denominator.subtract(numerator), denominator, true);
  }

  /**
   * Returns -this.
   */
  public BigFraction negate()
  {
    return new BigFraction(numerator.negate(), denominator, true);
  }

  /**
   * Returns -1, 0, or 1, representing the sign of this fraction.
   */
  public int signum()
  {
    return numerator.signum();
  }

  /**
   * Returns the absolute value of this.
   */
  public BigFraction abs()
  {
    return (signum() < 0 ? negate() : this);
  }

  /**
   * Returns a string representation of this, in the form
   * numerator/denominator.
   */
  public String toString()
  {
    return numerator.toString() + "/" + denominator.toString();
  }

  /**
   * Returns if this object is equal to another object.
   */
  public boolean equals(Object o)
  {
    if(!(o instanceof BigFraction))
      return false;

    BigFraction f = (BigFraction)o;
    return numerator.equals(f.numerator) && denominator.equals(f.denominator);
  }

  /**
   * Returns a hash code for this object.
   */
  public int hashCode()
  {
    //using the method generated by Eclipse, but streamlined a bit..
    return (31 + numerator.hashCode())*31 + denominator.hashCode();
  }

  /**
   * Returns a negative, zero, or positive number, indicating if this object
   * is less than, equal to, or greater than f, respectively.
   */
  public int compareTo(BigFraction f)
  {
    if(f == null)
      throw new IllegalArgumentException("Null argument");

    //easy case: this and f have different signs
    if(signum() != f.signum())
      return signum() - f.signum();

    //next easy case: this and f have the same denominator
    if(denominator.equals(f.denominator))
      return numerator.compareTo(f.numerator);

    //not an easy case, so first make the denominators equal then compare the numerators 
    return numerator.multiply(f.denominator).compareTo(denominator.multiply(f.numerator));
  }

  /**
   * Returns the smaller of this and f.
   */
  public BigFraction min(BigFraction f)
  {
    if(f == null)
      throw new IllegalArgumentException("Null argument");

    return (this.compareTo(f) <= 0 ? this : f);
  }

  /**
   * Returns the maximum of this and f.
   */
  public BigFraction max(BigFraction f)
  {
    if(f == null)
      throw new IllegalArgumentException("Null argument");

    return (this.compareTo(f) >= 0 ? this : f);
  }

  /**
   * Returns a positive BigFraction, greater than or equal to zero, and less than one.
   */
  public static BigFraction random()
  {
    return new BigFraction(Math.random());
  }

  public final BigInteger getNumerator() { return numerator; }
  public final BigInteger getDenominator() { return denominator; }

  //implementation of Number class.  may cause overflow.
  public byte   byteValue()   { return (byte) Math.max(Byte.MIN_VALUE,    Math.min(Byte.MAX_VALUE,    longValue())); }
  public short  shortValue()  { return (short)Math.max(Short.MIN_VALUE,   Math.min(Short.MAX_VALUE,   longValue())); }
  public int    intValue()    { return (int)  Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, longValue())); }
  public long   longValue()   { return Math.round(doubleValue()); }
  public float  floatValue()  { return (float)doubleValue(); }
  public double doubleValue() { return toBigDecimal(18).doubleValue(); }

  /**
   * Returns a BigDecimal representation of this fraction.  If possible, the
   * returned value will be exactly equal to the fraction.  If not, the BigDecimal
   * will have a scale large enough to hold the same number of significant figures
   * as both numerator and denominator, or the equivalent of a double-precision
   * number, whichever is more.
   */
  public BigDecimal toBigDecimal()
  {
    //Implementation note:  A fraction can be represented exactly in base-10 iff its
    //denominator is of the form 2^a * 5^b, where a and b are nonnegative integers.
    //(In other words, if there are no prime factors of the denominator except for
    //2 and 5, or if the denominator is 1).  So to determine if this denominator is
    //of this form, continually divide by 2 to get the number of 2's, and then
    //continually divide by 5 to get the number of 5's.  Afterward, if the denominator
    //is 1 then there are no other prime factors.

    //Note: number of 2's is given by the number of trailing 0 bits in the number
    int twos = denominator.getLowestSetBit();
    BigInteger tmpDen = denominator.shiftRight(twos); // x / 2^n === x >> n

    final BigInteger FIVE = BigInteger.valueOf(5);
    int fives = 0;
    BigInteger[] divMod = null;

    //while(tmpDen % 5 == 0) { fives++; tmpDen /= 5; }
    while(BigInteger.ZERO.equals((divMod = tmpDen.divideAndRemainder(FIVE))[1]))
    {
      fives++;
      tmpDen = divMod[0];
    }

    if(BigInteger.ONE.equals(tmpDen))
    {
      //This fraction will terminate in base 10, so it can be represented exactly as
      //a BigDecimal.  We would now like to make the fraction of the form
      //unscaled / 10^scale.  We know that 2^x * 5^x = 10^x, and our denominator is
      //in the form 2^twos * 5^fives.  So use max(twos, fives) as the scale, and
      //multiply the numerator and deminator by the appropriate number of 2's or 5's
      //such that the denominator is of the form 2^scale * 5^scale.  (Of course, we
      //only have to actually multiply the numerator, since all we need for the
      //BigDecimal constructor is the scale.
      BigInteger unscaled = numerator;
      int scale = Math.max(twos, fives);

      if(twos < fives)
        unscaled = unscaled.shiftLeft(fives - twos); //x * 2^n === x << n
      else if (fives < twos)
        unscaled = unscaled.multiply(FIVE.pow(twos - fives));

      return new BigDecimal(unscaled, scale);
    }

    //else: this number will repeat infinitely in base-10.  So try to figure out
    //a good number of significant digits.  Start with the number of digits required
    //to represent the numerator and denominator in base-10, which is given by
    //bitLength / log[2](10).  (bitLenth is the number of digits in base-2).
    final double LG10 = 3.321928094887362; //Precomputed ln(10)/ln(2), a.k.a. log[2](10)
    int precision = Math.max(numerator.bitLength(), denominator.bitLength());
    precision = (int)Math.ceil(precision / LG10);

    //If the precision is less than 18 digits, use 18 digits so that the number
    //will be at least as accurate as a cast to a double.  For example, with
    //the fraction 1/3, precision will be 1, giving a result of 0.3.  This is
    //quite a bit different from what a user would expect.
    if(precision < 18)
      precision = 18;

    return toBigDecimal(precision);
  }

  /**
   * Returns a BigDecimal representation of this fraction, with a given precision.
   * @param precision  the number of significant figures to be used in the result.
   */
  public BigDecimal toBigDecimal(int precision)
  {
    return new BigDecimal(numerator).divide(new BigDecimal(denominator), new MathContext(precision, RoundingMode.HALF_EVEN));
  }

  //--------------------------------------------------------------------------
  //  PRIVATE FUNCTIONS
  //--------------------------------------------------------------------------

  /**
   * Private constructor, used when you can be certain that the fraction is already in
   * lowest terms.  No check is done to reduce numerator/denominator.  A check is still
   * done to maintain a positive denominator.
   * 
   * @param throwaway  unused variable, only here to signal to the compiler that this
   *                   constructor should be used.
   */
  private BigFraction(BigInteger numerator, BigInteger denominator, boolean throwaway)
  {
    if(denominator.signum() < 0)
    {
      this.numerator = numerator.negate();
      this.denominator = denominator.negate();
    }
    else
    {
      this.numerator = numerator;
      this.denominator = denominator;
    }
  }

}
61
ответ дан Kip 24 November 2019 в 05:48
поделиться

Начальный комментарий:

Никогда запись это:

if ( condition ) statement;

Это намного лучше

if ( condition ) { statement };

, Просто создают для создания хорошей привычки.

Путем создания класса неизменным, как предложено, можно также использовать в своих интересах двойное для выполнения равняния, и хэш-код и compareTo операции

Вот моя быстрая грязная версия:

public final class Fraction implements Comparable {

    private final int numerator;
    private final int denominator;
    private final Double internal;

    public static Fraction createFraction( int numerator, int denominator ) { 
        return new Fraction( numerator, denominator );
    }

    private Fraction(int numerator, int denominator) {
        this.numerator   = numerator;
        this.denominator = denominator;
        this.internal = ((double) numerator)/((double) denominator);
    }


    public int getNumerator() {
        return this.numerator;
    }

    public int getDenominator() {
        return this.denominator;
    }


    private double doubleValue() {
        return internal;
    }

    public int compareTo( Object o ) {
        if ( o instanceof Fraction ) { 
            return internal.compareTo( ((Fraction)o).internal );
        }
        return 1;
    }

    public boolean equals( Object o ) {
          if ( o instanceof Fraction ) {  
             return this.internal.equals( ((Fraction)o).internal );
          } 
          return false;
    }

    public int hashCode() { 
        return internal.hashCode();
    }



    public String toString() { 
        return String.format("%d/%d", numerator, denominator );
    }

    public static void main( String [] args ) { 
        System.out.println( Fraction.createFraction( 1 , 2 ) ) ;
        System.out.println( Fraction.createFraction( 1 , 2 ).hashCode() ) ;
        System.out.println( Fraction.createFraction( 1 , 2 ).compareTo( Fraction.createFraction(2,4) ) ) ;
        System.out.println( Fraction.createFraction( 1 , 2 ).equals( Fraction.createFraction(4,8) ) ) ;
        System.out.println( Fraction.createFraction( 3 , 9 ).equals( Fraction.createFraction(1,3) ) ) ;
    }       

}

О статическом методе фабрики, может быть полезно позже при разделении на подклассы Части для обработки более сложных вещей, или если Вы решаете использовать пул для наиболее часто используемых объектов.

Это не может иметь место, я просто хотел указать на него.:)

См. Эффективный Java первый объект.

0
ответ дан OscarRyz 24 November 2019 в 05:48
поделиться

Используйте Рациональный класс от библиотека JScience. Это - лучшая вещь для дробной арифметики я замеченный в Java.

1
ответ дан Alexander Temerev 24 November 2019 в 05:48
поделиться

Практика уборки, которую я люблю, должна только иметь только один возврат.

 public int compareTo(Fraction frac) {
        int result = 0
        double t = this.doubleValue();
        double f = frac.doubleValue();
        if(t>f) 
           result = 1;
        else if(f>t) 
           result -1;
        return result;
    }
1
ответ дан Milhous 24 November 2019 в 05:48
поделиться

Я буду третий или пятый или безотносительно рекомендации для того, чтобы сделать Вашу часть неизменной. Я также рекомендовал бы иметь его, расширяются класс Номер . Я, вероятно, посмотрел бы Двойной класс, так как Вы, вероятно, собираетесь хотеть реализовать многие из тех же методов.

необходимо, вероятно, также реализовать Сопоставимый и сериализуемый , так как это поведение будет, вероятно, ожидаться. Таким образом необходимо будет реализовать compareTo (). Необходимо будет также переопределить, равняется (), и я не могу подчеркнуть достаточно сильно, что Вы также переопределяете хэш-код (). Это могло бы быть одним из нескольких случаев, хотя, где Вы не хотите compareTo () и равняетесь (), чтобы быть последовательными, так как части, приводимые друг другу, не обязательно равны.

1
ответ дан James 24 November 2019 в 05:48
поделиться

У Timothy Budd есть прекрасная реализация Рационального класса в его "Структурах данных в C++". Различный язык, конечно, но это портирует на Java очень приятно.

я рекомендовал бы большему количеству конструкторов. Конструктор по умолчанию имел бы числитель 0, знаменатель 1. Единственный конструктор аргумента принял бы знаменатель 1. Думайте, как Ваши пользователи могли бы использовать этот класс.

Никакая проверка на нулевой знаменатель? Программирование согласно контракту сделало бы, чтобы Вы добавили его.

1
ответ дан duffymo 24 November 2019 в 05:48
поделиться

Конкретно : существует ли лучший способ обработать быть переданным нулевого знаменателя? Установка знаменателя к 1 является чувствами, могущественными произвольный. Как я могу сделать это правильно?

я сказал бы, бросают ArithmeticException для деления нулем, так как это действительно, что происходит:

public Fraction(int numerator, int denominator) {
    if(denominator == 0)
        throw new ArithmeticException("Divide by zero.");
    this.numerator = numerator;
    this.denominator = denominator;
}

Вместо "Делятся на нуль". Вы могли бы хотеть заставить в сообщении быть сказанным, "Делятся на нуль: Знаменатель для Части является нулем".

2
ответ дан Kip 24 November 2019 в 05:48
поделиться

Как только Вы создали дробный объект, почему Вы хотели бы позволить другим объектам установить числитель или знаменатель? Я думал бы, что они должны быть только для чтения. Это делает объект неизменным...

Также... обнуление знаменателя должно выдать исключение недействительного аргумента (я не знаю то, что это находится в Java)

1
ответ дан Jason Punyon 24 November 2019 в 05:48
поделиться

У Вас уже есть функция compareTo... Я реализовал бы интерфейс Comparable.

май не действительно имеет значение для того, что Вы собираетесь сделать с ним все же.

2
ответ дан Dave Costa 24 November 2019 в 05:48
поделиться

как я улучшил бы тот код:

  1. конструктор на основе Строковой Части (Представляют s в виде строки)//ожидают "число/число"
  2. , Часть конструктора копии (Дробная копия)
  3. переопределяет метод клона
  4. реализации равняние, toString и методы хэш-кода
  5. реализации интерфейс java.io. Сериализуемый, Сопоставимый
  6. метод "удваивает getDoubleValue ()"
  7. , метод добавлять/делить/и т.д...
  8. я сделал бы тот класс как неизменный (никакие методы set)
2
ответ дан Pierre 24 November 2019 в 05:48
поделиться

При умножении числителя и знаменателя одной Части со знаменателем другой и наоборот Вы заканчиваете с двумя частями (которые являются все еще теми же значениями) с тем же знаменателем, и можно сравнить числители непосредственно. Поэтому Вы не должны были бы вычислять двойное значение:

public int compareTo(Fraction frac) {
    int t = this.numerator * frac.getDenominator();
    int f = frac.getNumerator() * this.denominator;
    if(t>f) return 1;
    if(f>t) return -1;
    return 0;
}
3
ответ дан Francisco Canedo 24 November 2019 в 05:48
поделиться

Существует несколько способов улучшить это или любой тип значения:

  • Делают Ваш класс неизменным , включая создание числителя и финала знаменателя
  • Автоматически преобразовывают части в каноническую форму , например, 2/4-> Реализация 1/2
  • toString ()
  • Реализация "общедоступная статическая Часть valueOf (Представьте s в виде строки)" для преобразования от строк до частей. Реализуйте подобные методы фабрики для преобразования из интервала, дважды, и т.д.
  • дополнение Реализации, умножение, и т.д.
  • Добавляют конструктора от целых чисел
  • , Переопределение равняется/хэш-код
  • , Считают Часть создания интерфейсом с реализацией, которая переключается на BigInteger по мере необходимости
  • , Рассматривают разделение на подклассы , Номер
  • Рассматривает включая именованные константы для общих ценностей как 0, и 1
  • Считают создание его сериализуемым
  • , Тест для деления на нуль
  • Документирует Ваш API

В основном, смотрит на API для других классов значения как Двойной , Целое число и делает то, что они делают:)

4
ответ дан Dave Ray 24 November 2019 в 05:48
поделиться

Одно очень незначительное улучшение могло потенциально быть должно сохранить двойное значение, что Вы являетесь вычислительными так, чтобы Вы только вычислили его на первом доступе. Это не будет большой победой, если Вы не получите доступ к этому числу много, но не чрезмерно трудно сделать, также.

Одна дополнительная точка могла бы быть проверкой ошибок, которую Вы делаете в знаменателе..., Вы автоматически изменяетесь от 0 до 1. Не уверенный, если это корректно для Вашего конкретного приложения, но в целом если кто-то пытается разделиться на 0, что-то очень неправильно. Я позволил этому выдать исключение (специализированное исключение, если Вы чувствуете, что это необходимо), а не измените значение на вид произвольным способом, который не известен пользователю.

В constrast с некоторыми другими комментариями, о добавляющих методах для добавления вычитают, и т.д...., так как Вы не упоминали, что нуждались в них, я предполагаю, что Вы не делаете. И если Вы не создаете библиотеку, которая действительно будет используемой во многих местах или другими людьми, пойдите с YAGNI (Вы не собираетесь нуждаться в нем, таким образом, это не должно быть там.)

4
ответ дан Beska 24 November 2019 в 05:48
поделиться

я должен буду заказать им от самого маленького до самого большого, поэтому в конечном счете я должен буду представить их как двойное также

Не строго необходимый. (На самом деле, если Вы хотите обработать равенство правильно, не полагайтесь дважды для работы правильно.), Если b*d положителен, a/b < c/d, если реклама < до н.э, Если существуют отрицательные включенные целые числа, который может быть обработан соответственно...

я мог бы переписать как:

public int compareTo(Fraction frac)
{
    // we are comparing this=a/b with frac=c/d 
    // by multiplying both sides by bd.
    // If bd is positive, then a/b < c/d <=> ad < bc.
    // If bd is negative, then a/b < c/d <=> ad > bc.
    // If bd is 0, then you've got other problems (either b=0 or d=0)
    int d = frac.getDenominator();
    long ad = (long)this.numerator * d;
    long bc = (long)this.denominator * frac.getNumerator();
    long diff = ((long)d*this.denominator > 0) ? (ad-bc) : (bc-ad);
    return (diff > 0 ? 1 : (diff < 0 ? -1 : 0));
}

использование long здесь должно гарантировать, что нет переполнения при умножении двух больших int дескриптор с, Если можно гарантировать, что знаменатель является всегда неотрицательным (если это отрицательно, просто инвертируйте и числитель и знаменатель), тогда можно избавиться от необходимости проверить, положителен ли b*d, и сохраните несколько шагов. Я не уверен, какое поведение Вы ищете с нулевым знаменателем.

Не уверенный то, как производительность выдерживает сравнение с использованием, удваивается для сравнения. (то есть, если Вы заботитесь о производительности так очень), Вот метод тестирования, который я раньше проверял. (Кажется, работает правильно.)

public static void main(String[] args)
{
    int a = Integer.parseInt(args[0]);
    int b = Integer.parseInt(args[1]);
    int c = Integer.parseInt(args[2]);
    int d = Integer.parseInt(args[3]);
    Fraction f1 = new Fraction(a,b); 
    Fraction f2 = new Fraction(c,d);
    int rel = f1.compareTo(f2);
    String relstr = "<=>";
    System.out.println(a+"/"+b+" "+relstr.charAt(rel+1)+" "+c+"/"+d);
}

(p.s. Вы мог бы полагать, что реструктуризация реализовала Comparable или Comparator для Вашего класса.)

5
ответ дан Jason S 24 November 2019 в 05:48
поделиться
  • Это довольно бессмысленно без арифметических методов, любят, добавляют () и умножаются (), и т.д.
  • необходимо определенно переопределить, равняется () и хэш-код ().
  • необходимо или добавить метод, чтобы нормализовать часть или сделать это автоматически. Думайте о том, хотите ли Вы, чтобы 1/2 и 2/4 считались тем же или не - это имеет последствия для равняния (), хэш-код () и compareTo () методы.
5
ответ дан Michael Borgwardt 24 November 2019 в 05:48
поделиться

Ну, для одного я избавился бы от методов set и сделал бы Части неизменными.

Вы, вероятно, также захотите, чтобы методы добавили, вычли, и т.д., и возможно некоторый способ получить представление в различных Форматах строки.

РЕДАКТИРОВАНИЕ: я, вероятно, отметил бы поля как 'финал' для передачи сигналов о моем намерении, но я предполагаю это не имеет большого значения...

7
ответ дан Outlaw Programmer 24 November 2019 в 05:48
поделиться

Сделайте его неизменным типом! Значение части не изменяется - половина не становится одной третью, например. Вместо setDenominator у Вас мог быть withDenominator, который возвращается новый часть, которая имеет тот же числитель, но указанный знаменатель.

Жизнь очень легче с неизменными типами.

Переопределение равняется, и хэш-код был бы разумен также, таким образом, это может использоваться в картах и наборах. Запретите точки Программиста об арифметических операторах, и строковое форматирование хороши также.

Как общее руководство, взгляните на BigInteger и BigDecimal. Они не делают того же самого, но они достаточно подобны, чтобы дать Вам хорошие идеи.

24
ответ дан Jon Skeet 24 November 2019 в 05:48
поделиться

я пытаюсь работать с правильными дробями в Java.

Apache Математика палаты общин имела Часть класс в течение достаточно долгого времени. Большинство раз ответ на, "У мальчика, которого я желаю Java, было что-то как X в оперативной библиотеке!" может быть найден под зонтиком библиотека Apache Commons .

28
ответ дан yawmark 24 November 2019 в 05:48
поделиться

На самом деле, примерьте это для размера. Это работает, но может иметь некоторые проблемы:

public class BigRational extends Number implements Comparable<BigRational>, Serializable {
    public final static BigRational ZERO = new BigRational(BigInteger.ZERO, BigInteger.ONE);
    private final static long serialVersionUID = 1099377265582986378L;

    private final BigInteger numerator, denominator;

    private BigRational(BigInteger numerator, BigInteger denominator) {
        this.numerator = numerator;
        this.denominator = denominator;
    }

    private static BigRational canonical(BigInteger numerator, BigInteger denominator, boolean checkGcd) {
        if (denominator.signum() == 0) {
            throw new IllegalArgumentException("denominator is zero");
        }
        if (numerator.signum() == 0) {
            return ZERO;
        }
        if (denominator.signum() < 0) {
            numerator = numerator.negate();
            denominator = denominator.negate();
        }
        if (checkGcd) {
            BigInteger gcd = numerator.gcd(denominator);
            if (!gcd.equals(BigInteger.ONE)) {
                numerator = numerator.divide(gcd);
                denominator = denominator.divide(gcd);
            }
        }
        return new BigRational(numerator, denominator);
    }

    public static BigRational getInstance(BigInteger numerator, BigInteger denominator) {
        return canonical(numerator, denominator, true);
    }

    public static BigRational getInstance(long numerator, long denominator) {
        return canonical(new BigInteger("" + numerator), new BigInteger("" + denominator), true);
    }

    public static BigRational getInstance(String numerator, String denominator) {
        return canonical(new BigInteger(numerator), new BigInteger(denominator), true);
    }

    public static BigRational valueOf(String s) {
        Pattern p = Pattern.compile("(-?\\d+)(?:.(\\d+)?)?0*(?:e(-?\\d+))?");
        Matcher m = p.matcher(s);
        if (!m.matches()) {
            throw new IllegalArgumentException("Unknown format '" + s + "'");
        }

        // this translates 23.123e5 to 25,123 / 1000 * 10^5 = 2,512,300 / 1 (GCD)
        String whole = m.group(1);
        String decimal = m.group(2);
        String exponent = m.group(3);
        String n = whole;

        // 23.123 => 23123
        if (decimal != null) {
            n += decimal;
        }
        BigInteger numerator = new BigInteger(n);

        // exponent is an int because BigInteger.pow() takes an int argument
        // it gets more difficult if exponent needs to be outside {-2 billion,2 billion}
        int exp = exponent == null ? 0 : Integer.valueOf(exponent);
        int decimalPlaces = decimal == null ? 0 : decimal.length();
        exp -= decimalPlaces;
        BigInteger denominator;
        if (exp < 0) {
            denominator = BigInteger.TEN.pow(-exp);
        } else {
            numerator = numerator.multiply(BigInteger.TEN.pow(exp));
            denominator = BigInteger.ONE;
        }

        // done
        return canonical(numerator, denominator, true);
    }

    // Comparable
    public int compareTo(BigRational o) {
        // note: this is a bit of cheat, relying on BigInteger.compareTo() returning
        // -1, 0 or 1.  For the more general contract of compareTo(), you'd need to do
        // more checking
        if (numerator.signum() != o.numerator.signum()) {
            return numerator.signum() - o.numerator.signum();
        } else {
            // oddly BigInteger has gcd() but no lcm()
            BigInteger i1 = numerator.multiply(o.denominator);
            BigInteger i2 = o.numerator.multiply(denominator);
            return i1.compareTo(i2); // expensive!
        }
    }

    public BigRational add(BigRational o) {
        if (o.numerator.signum() == 0) {
            return this;
        } else if (numerator.signum() == 0) {
            return o;
        } else if (denominator.equals(o.denominator)) {
            return new BigRational(numerator.add(o.numerator), denominator);
        } else {
            return canonical(numerator.multiply(o.denominator).add(o.numerator.multiply(denominator)), denominator.multiply(o.denominator), true);
        }
    }


    public BigRational multiply(BigRational o) {
        if (numerator.signum() == 0 || o.numerator.signum( )== 0) {
            return ZERO;
        } else if (numerator.equals(o.denominator)) {
            return canonical(o.numerator, denominator, true);
        } else if (o.numerator.equals(denominator)) {
            return canonical(numerator, o.denominator, true);
        } else if (numerator.negate().equals(o.denominator)) {
            return canonical(o.numerator.negate(), denominator, true);
        } else if (o.numerator.negate().equals(denominator)) {
            return canonical(numerator.negate(), o.denominator, true);
        } else {
            return canonical(numerator.multiply(o.numerator), denominator.multiply(o.denominator), true);
        }
    }

    public BigInteger getNumerator() { return numerator; }
    public BigInteger getDenominator() { return denominator; }
    public boolean isInteger() { return numerator.signum() == 0 || denominator.equals(BigInteger.ONE); }
    public BigRational negate() { return new BigRational(numerator.negate(), denominator); }
    public BigRational invert() { return canonical(denominator, numerator, false); }
    public BigRational abs() { return numerator.signum() < 0 ? negate() : this; }
    public BigRational pow(int exp) { return canonical(numerator.pow(exp), denominator.pow(exp), true); }
    public BigRational subtract(BigRational o) { return add(o.negate()); }
    public BigRational divide(BigRational o) { return multiply(o.invert()); }
    public BigRational min(BigRational o) { return compareTo(o) <= 0 ? this : o; }
    public BigRational max(BigRational o) { return compareTo(o) >= 0 ? this : o; }

    public BigDecimal toBigDecimal(int scale, RoundingMode roundingMode) {
        return isInteger() ? new BigDecimal(numerator) : new BigDecimal(numerator).divide(new BigDecimal(denominator), scale, roundingMode);
    }

    // Number
    public int intValue() { return isInteger() ? numerator.intValue() : numerator.divide(denominator).intValue(); }
    public long longValue() { return isInteger() ? numerator.longValue() : numerator.divide(denominator).longValue(); }
    public float floatValue() { return (float)doubleValue(); }
    public double doubleValue() { return isInteger() ? numerator.doubleValue() : numerator.doubleValue() / denominator.doubleValue(); }

    @Override
    public String toString() { return isInteger() ? String.format("%,d", numerator) : String.format("%,d / %,d", numerator, denominator); }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        BigRational that = (BigRational) o;

        if (denominator != null ? !denominator.equals(that.denominator) : that.denominator != null) return false;
        if (numerator != null ? !numerator.equals(that.numerator) : that.numerator != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = numerator != null ? numerator.hashCode() : 0;
        result = 31 * result + (denominator != null ? denominator.hashCode() : 0);
        return result;
    }

    public static void main(String args[]) {
        BigRational r1 = BigRational.valueOf("3.14e4");
        BigRational r2 = BigRational.getInstance(111, 7);
        dump("r1", r1);
        dump("r2", r2);
        dump("r1 + r2", r1.add(r2));
        dump("r1 - r2", r1.subtract(r2));
        dump("r1 * r2", r1.multiply(r2));
        dump("r1 / r2", r1.divide(r2));
        dump("r2 ^ 2", r2.pow(2));
    }

    public static void dump(String name, BigRational r) {
        System.out.printf("%s = %s%n", name, r);
        System.out.printf("%s.negate() = %s%n", name, r.negate());
        System.out.printf("%s.invert() = %s%n", name, r.invert());
        System.out.printf("%s.intValue() = %,d%n", name, r.intValue());
        System.out.printf("%s.longValue() = %,d%n", name, r.longValue());
        System.out.printf("%s.floatValue() = %,f%n", name, r.floatValue());
        System.out.printf("%s.doubleValue() = %,f%n", name, r.doubleValue());
        System.out.println();
    }
}

Вывод:

r1 = 31,400
r1.negate() = -31,400
r1.invert() = 1 / 31,400
r1.intValue() = 31,400
r1.longValue() = 31,400
r1.floatValue() = 31,400.000000
r1.doubleValue() = 31,400.000000

r2 = 111 / 7
r2.negate() = -111 / 7
r2.invert() = 7 / 111
r2.intValue() = 15
r2.longValue() = 15
r2.floatValue() = 15.857142
r2.doubleValue() = 15.857143

r1 + r2 = 219,911 / 7
r1 + r2.negate() = -219,911 / 7
r1 + r2.invert() = 7 / 219,911
r1 + r2.intValue() = 31,415
r1 + r2.longValue() = 31,415
r1 + r2.floatValue() = 31,415.857422
r1 + r2.doubleValue() = 31,415.857143

r1 - r2 = 219,689 / 7
r1 - r2.negate() = -219,689 / 7
r1 - r2.invert() = 7 / 219,689
r1 - r2.intValue() = 31,384
r1 - r2.longValue() = 31,384
r1 - r2.floatValue() = 31,384.142578
r1 - r2.doubleValue() = 31,384.142857

r1 * r2 = 3,485,400 / 7
r1 * r2.negate() = -3,485,400 / 7
r1 * r2.invert() = 7 / 3,485,400
r1 * r2.intValue() = 497,914
r1 * r2.longValue() = 497,914
r1 * r2.floatValue() = 497,914.281250
r1 * r2.doubleValue() = 497,914.285714

r1 / r2 = 219,800 / 111
r1 / r2.negate() = -219,800 / 111
r1 / r2.invert() = 111 / 219,800
r1 / r2.intValue() = 1,980
r1 / r2.longValue() = 1,980
r1 / r2.floatValue() = 1,980.180176
r1 / r2.doubleValue() = 1,980.180180

r2 ^ 2 = 12,321 / 49
r2 ^ 2.negate() = -12,321 / 49
r2 ^ 2.invert() = 49 / 12,321
r2 ^ 2.intValue() = 251
r2 ^ 2.longValue() = 251
r2 ^ 2.floatValue() = 251.448975
r2 ^ 2.doubleValue() = 251.448980
58
ответ дан 9 revs, 2 users 100% 24 November 2019 в 05:48
поделиться

Если Вы чувствуете себя предприимчивыми, смотрите на JScience. Это имеет Rational класс, который представляет части.

2
ответ дан Zach Scrivena 24 November 2019 в 05:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: