6

特定の係数で縦横比 (の形式) を計算するにはどうすればよいinteger:integerですか?

たとえば、アスペクト比 16:9 の係数は 1.778 です。これは、16 / 9 = 1.778 であるためです。しかし、どうすればその係数で比率を見つけることができますか? そう

Dimension getAspectRatio(double factor) {
    ...
}

public static void main(String[] arguments) {
    Dimension d = getAspectRatio(16d / 9d);
    System.out.println(d.width + ":" + d.height);
}

戻るべき

16:9
4

8 に答える 8

12

これは非常に遅い返信ですが、私はこれをはるかに簡単な方法で解決しました。他の人が感謝することを知っています.

アスペクト比 (10 進数に相当) を知っているので、画面の解像度を既に知っていると仮定しています。画面の幅と高さの最大公約数を解くことで、アスペクト比 (整数:整数) を見つけることができます。

public int greatestCommonFactor(int width, int height) {
    return (height == 0) ? width : greatestCommonFactor(height, width % height);
}

画面の幅と高さの最大公約数を返します。実際の縦横比を求めるには、画面の幅と高さを最大公約数で割ります。そう...

int screenWidth = 1920;
int screenHeight = 1080;

int factor = greatestCommonFactor(screenWidth, screenHeight);

int widthRatio = screenWidth / factor;
int heightRatio = screenHeight / factor;

System.out.println("Resolution: " + screenWidth + "x" + screenHeight;
System.out.println("Aspect Ratio: " + widthRatio + ":" + heightRatio;
System.out.println("Decimal Equivalent: " + widthRatio / heightRatio;

これは以下を出力します:

Resolution: 1920x1080
Aspect Ratio: 16:9
Decimal Equivalent: 1.7777779

お役に立てれば。

注: これは、一部の解像度では機能しません。コメントには詳細情報が含まれています。

于 2015-01-03T10:41:00.303 に答える
10

免責事項: これらのアルゴリズムは愚かで非効率的です。きっと他にもっといいのがある...

近似を見つけるためのばかげた、単純な (あまり効率的ではない) アルゴリズムは次のとおりです。

double ratio = 1.778;
double bestDelta = Double.MAX_VALUE;
int bestI = 0;
int bestJ = 0;

for (int i = 1; i < 100; i++) {
  for (int j = 1; j < 100; j++) {
    double newDelta = Math.abs((double) i / (double) j - ratio);
    if (newDelta < bestDelta) {
      bestDelta = newDelta;
      bestI = i;
      bestJ = j;
    }
  }
}

System.out.println("Closest ratio: " + bestI + "/" + bestJ);
System.out.println("Ratio        : " + ((double) bestI / (double) bestJ));
System.out.println("Inaccurate by: " + bestDelta); 

出力。

Closest ratio: 16/9
Ratio        : 1.7777777777777777
Inaccurate by: 2.2222222222234578E-4

更新: 代替アルゴリズム

近似に近づこうとする代替アルゴリズムを考えました。もちろん、それはまだあまり効率的ではありません...

double bestDelta = Double.MAX_VALUE;
int i = 1;
int j = 1;
int bestI = 0;
int bestJ = 0;

for (int iterations = 0; iterations < 100; iterations++) {
  double delta = (double) i / (double) j - ratio;

  // Optionally, quit here if delta is "close enough" to zero
  if (delta < 0) i++;
  else j++;

  double newDelta = Math.abs((double) i / (double) j - ratio);
  if (newDelta < bestDelta) {
    bestDelta = newDelta;
    bestI = i;
    bestJ = j;
  }
}

System.out.println("Closest ratio: " + bestI + "/" + bestJ);
System.out.println("Ratio        : " + ((double) bestI / (double) bestJ));
System.out.println("Inaccurate by: " + bestDelta);

出力は同じです

効率的なアルゴリズムに出くわした場合は、ここに投稿します:-)

于 2011-09-16T08:54:57.787 に答える
7

double は実際の (正確な) 分数を表していない可能性があるため、これは一般的には不可能です。他の回答で示唆されているように、ヒューリスティックまたはブルートフォースに頼る必要があります。

正確な小数展開とピリオドがあれば、それを解決できます。

ペンと紙の方法は次のとおりです。

  1. から始めたとします1.77777...(これは 16/9 ですが、それを知らなかったと仮定しましょう)

  2. ピリオドは7(1 桁) であるため、10 を掛けます (つまり、小数点を 1 ステップ右に移動します)。

    10n = 17.77777...
    
  3. を計算することで、繰り返し部分をキャンセルできるようになりました10n - n

    10n - n = 17.77777... - 1.77777... = 16
    
  4. n利回りの解決n = 16/9

これをコードに変換するには、10 進展開の期間の開始と長さを把握する必要があります。数値は通常 のようになるため、それ自体が厄介な問題になります0.16666667

于 2011-09-16T08:50:53.823 に答える
3

Best rational approximationこれは、Farey シーケンスに基づいてを見つける Scala での実装です。このアルゴリズムは @AakashM によって提案され、John D. Cook の Python 実装David Weber の C++ の修正から翻訳されました。

/**
 * Calculates the `Best rational approximation` based on the Farey sequence.
 *
 * Translated from John D. Cook's Python implementation and David
 * Weber's C++ modification.
 *
 * @param x A value to be approximated by two integers.
 * @param eps The required precision such that abs(x-a/b) < eps. Eps > 0.
 * @param n The maximum size of the numerator allowed.
 * @return The best rational approximation for x.
 */
def farey(x: Double, eps: Double, n: Int): (Int, Int) = {

  @tailrec
  def iterate(a: Int, b: Int, c: Int, d: Int): (Int, Int) = {
    if (b <= n && d <= n) {
      val mediant = (a + c).toDouble / (b + d).toDouble
      if (Math.abs(x - mediant) < eps) {
        if (b + d <= n) {
          (a + c) -> (b + d)
        } else if (d > b) {
          c -> d
        } else {
          a -> b
        }
      } else if (x > mediant) {
        iterate(a + c, b + d, c, d)
      } else {
        iterate(a, b, a + c, b + d)
      }
    }
    else if (b > n) c -> d
    else a -> b
  }

  iterate(0, 1, 1, 0)
}

いくつかのテストも含む要旨を作成しました。

于 2015-10-14T10:42:34.907 に答える
1

これは一次方程式です。一般に、線形方程式に2 つの未知数を含めることはできません。

于 2011-09-16T08:54:45.950 に答える
1

実際には、形状のすべての要因はa/b、有限の比率または無限だが周期的な比率として表されます (ただしa、 とbは整数です)。ただし、期間はかなり長くなる可能性があります。期間が少なくとも倍精度の半分未満である場合は、それを検出して正確な比率を見つけることができます。または、最善の推測を試みることもできます。

于 2011-09-16T08:58:21.387 に答える
0

アスペクト比は実数 (たとえば 1.85:1) になる可能性があるため、要因からアスペクト比を「推測」することは不可能です。

しかし、おそらく 10 の一般的に使用されるアスペクト比があります。ファクターとアスペクト比の表を簡単に作成できます。

于 2011-09-16T08:58:46.883 に答える