[JAVA] Une histoire sur la rédaction d'un calcul de ratio lors d'une session d'étude en interne

introduction

Je pense qu'il y a des situations où la valeur est modifiée tout en maintenant le rapport, comme l'agrandissement / la réduction de l'image. Cette fois, dans une telle situation, j'ai essayé de résoudre les problèmes suivants avec de jeunes employés. Au fait, si vous recherchez sur le net, la réponse sortira, j'ai donc interdit la recherche sur le net.


problème

  1. Trouvez le rapport de deux valeurs entières x et y
  2. Trouvez la valeur agrandie / réduite avec le plus grand de x et y comme valeur maximale max.

Solution 1: exclusion

Tout d'abord, la méthode la plus simple était de trouver le rapport en utilisant une méthode de division simple.

Exemple.


x = 100
y = 10
x / y = 10
x est 10 fois y
Autrement dit, x:y=10:1

Je pense que c'est intuitif et facile à comprendre, mais cela a l'inconvénient de perdre en précision quand il n'est pas divisible par cette méthode.

Exemple.


x = 100
y = 30
x / y = 3.3333...
X est-il environ 3 fois y?

Dans ce cas, "x: y = 10: 3" devrait convenir, mais avec le rapport obtenu en utilisant la méthode de division simple, il existe un problème selon lequel y ne devient pas 150 lorsque max est défini sur 500 dans le problème suivant. Cela se produira. Je pense qu'il est fourmi de le traiter par traitement fractionnaire en fonction de la tolérance de l'erreur.


Solution 2: engagement maximum

Ensuite, en tant que solution préparée à l'avance, j'ai présenté une méthode pour trouver le ratio en divisant chacun de x et y par l'engagement maximal.

Exemple.


x = 100
y = 30
Engagement maximum= 10
x : y = x /Engagement maximum: y /Engagement maximum
Autrement dit, x:y=10:3

Avec cette méthode, vous pourrez calculer le rapport sous forme d'entier.


Méthode de division mutuelle euclidienne

Comme méthode pour trouver l'engagement maximal, "[Méthode de division mutuelle euclidienne](https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%" AA% E3% 83% 83% E3% 83% 89% E3% 81% AE% E4% BA% 92% E9% 99% A4% E6% B3% 95) ».

Pour résumer brièvement, la procédure suivante sera répétée.

  1. Divisez la grande valeur par la petite valeur
  2. S'il y a un reste, divisez la petite valeur d'origine par le reste qui est sorti.

Récurrence et boucle

Il existe deux manières d'écrire un traitement itératif: récursif et boucle. La reconnaissance peut provoquer un débordement de pile, mais vous pouvez écrire du code propre. Les boucles, en revanche, peuvent être du code redondant et peuvent conduire à une mauvaise visibilité lorsque les conditions deviennent complexes. Sachez également que si vous faites une erreur dans les conditions de sortie des deux, vous vous retrouverez dans une boucle infinie.


Optimisation des appels de queue

Dans les langages modernes, le débordement de pile récursif peut être éliminé par l'optimisation des appels de fin. Cependant, comme il s'agit d'une fonction de langage (compilateur), elle ne résout aucun langage, veuillez donc en tenir compte lorsque vous envisagez l'implémentation.


Dans ce cas

Uniquement à Kotlin, mais [Fibonatch Count](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3% J'ai essayé de confirmer en utilisant 83% 83% E3% 83% 81% E6% 95% B0).

val x = 1836311903
val y = 1134903170

Ce qui précède est le nombre maximal maximum de combinaisons de Fibonacci pouvant être spécifiées par Int, et même avec cela, le nombre d'essais n'était que de 45. Par conséquent, dans ce cas, il s'est avéré que les boucles récursives et les boucles pouvaient être utilisées sans aucune attention particulière.

Cependant, la récurrence lors de la réflexion sur la base d'un projet réel est une idée. Pour les équipes avec différents niveaux de compréhension du programme, du jeune au vétéran, n'est-il pas plus facile de comprendre les boucles à tous les niveaux dans un traitement itératif simple comme ce problème? C'était conclu. Bien sûr, si cela se complique, il sera difficile à comprendre même en boucle, il est donc nécessaire d'envisager des moyens d'améliorer la lisibilité, y compris la récurrence.


Exemple de code

Voici le code qui réécrit ce problème afin qu'il soit facile de comparer ce qui a été écrit dans chaque langue.


Kotlin

fun main(args: Array<String>) {
  val x = 30
  val y = 100
  val max = 500

  val gcdResult = gcd(x, y)
  val xRatio = x / gcdResult
  val yRatio = y / gcdResult
  println("Engagement maximum: $gcdResult => $xRatio:$yRatio")
  
  val largeResult = max
  val smallResult = getSmallerGcdPair(x, y, largeResult)
  if(x > y) {
    println("$x:$y => $largeResult:$smallResult")
  } else {
    println("$x:$y => $smallResult:$largeResult")
  }
}

fun gcd(xInput: Int, yInput: Int): Int {
  var largeVal = Math.max(xInput, yInput)
  var smallVal = Math.min(xInput, yInput)
  var remVal = 0

  do{
    remVal = largeVal % smallVal
    largeVal = smallVal
    smallVal = remVal
  } while(remVal > 0)

  return largeVal
}

fun getSmallerGcdPair(xRatio: Int, yRatio: Int, largeResult: Int): Int {
  var largeRatio = Math.max(xRatio, yRatio)
  var smallRatio = Math.min(xRatio, yRatio)

  return largeResult / largeRatio * smallRatio    
}

Swift

func main() {
  let x: Int = 30
  let y: Int = 100
  let max = 500

  let gcdResult = gcd(x, y)
  let xRatio = x / gcdResult
  let yRatio = y / gcdResult
  print("Engagement maximum: \(gcdResult) => \(xRatio) : \(yRatio)")

  let largeResult = max
  let smallResult = getSmallerGcdPair(xRatio, yRatio, largeResult)
  if(x > y) {
    print("\(x):\(y) => \(largeResult):\(smallResult)")
  } else {
    print("\(x):\(y) => \(smallResult):\(largeResult)")
  }
}

func gcd(_ xInput: Int, _ yInput: Int) -> Int {
  var largeVal = max(xInput, yInput)
  var smallVal = min(xInput, yInput)
  var remVal = 0

  repeat {
    remVal = largeVal % smallVal
    largeVal = smallVal
    smallVal = remVal
  } while remVal > 0

  return largeVal
}

func getSmallerGcdPair(_ xRatio: Int, _ yRatio: Int, _ largeResult: Int) -> Int {
  let largeRatio = max(xRatio, yRatio)
  let smallRatio = min(xRatio, yRatio)

  return largeResult / largeRatio * smallRatio
}

main()

PHP

<?php
const x = 30;
const y = 100;
const max = 500;

define('gcdResult', gcd(x, y));
define('xRatio', x / gcdResult);
define('yRatio', y / gcdResult);
echo "Engagement maximum: ".gcdResult." => ".xRatio.":".yRatio.PHP_EOL;

const largeResult = max;
define('smallResult', getSmallerGcdPair(xRatio, yRatio, largeResult));
if(x > y) {
  echo x.":".y." => ".largeResult.":".smallResult.PHP_EOL;
} else {
  echo x.":".y." => ".smallResult.":".largeResult.PHP_EOL;
}

function gcd($xInput, $yInput): int {
  $largeVal = max($xInput, $yInput);
  $smallVal = min($xInput, $yInput);
  $remVal = 0;

  do {
    $remVal = $largeVal % $smallVal;
    $largeVal = $smallVal;
    $smallVal = $remVal;
  } while($remVal > 0);
  
  return $largeVal;
}

function getSmallerGcdPair($xRatio, $yRatio, $largeResult): int {
  define('largeRatio', max($xRatio, $yRatio));
  define('smallRatio', min($xRatio, $yRatio));

  return $largeResult / largeRatio * smallRatio;
}

JavaScript

function main() {
  const x = 30
  const y = 100
  const max = 500

  const gcdResult = gcd(x, y)
  const xRatio = x / gcdResult
  const yRatio = y / gcdResult
  console.log(`Engagement maximum: ${gcdResult} => ${xRatio} : ${yRatio}`)

  const largeResult = max
  const smallResult = getSmallerGcdPair(xRatio, yRatio, largeResult)
  if(x > y) {
    console.log(`${x}:${y} => ${largeResult}:${smallResult}`)
  } else {
    console.log(`${x}:${y} => ${smallResult}:${largeResult}`)
  }
}

const gcd = (xInput, yInput) => {
  let largeVal = Math.max(xInput, yInput)
  let smallVal = Math.min(xInput, yInput)
  let remVal = 0

  do {
    remVal = largeVal % smallVal
    largeVal = smallVal
    smallVal = remVal
  } while(remVal > 0)

  return largeVal
}

const getSmallerGcdPair = (xRatio, yRatio, largeResult) => {
  const largeRatio = Math.max(xRatio, yRatio)
  const smallRatio = Math.min(xRatio, yRatio)

  return largeResult / largeRatio * smallRatio
}

main()

Java

import java.util.*;

public class Main {
  public static void main(String[] args) throws Exception {
    final int x = 30;
    final int y = 100;
    final int max = 500;

    final int gcdResult = gcd(x, y);
    final int xRatio = x / gcdResult;
    final int yRatio = y / gcdResult;
    System.out.println("Engagement maximum: " + gcdResult + " => " + xRatio + " : " + yRatio);

    final int largeResult = max;
    final int smallResult = getSmallerGcdPair(x, y, largeResult);
    if(x > y) {
      System.out.println(x + ":" + y + " => " + largeResult + ":" + smallResult);
    } else {
      System.out.println(x + ":" + y + " => " + smallResult + ":" + largeResult);
    }
  }

  private static int gcd(int xInput, int yInput) {
    int largeVal = Math.max(xInput, yInput);
    int smallVal = Math.min(xInput, yInput);
    int remVal = 0;

    do {
      remVal = largeVal % smallVal;
      largeVal = smallVal;
      smallVal = remVal;
    } while(remVal > 0);

    return largeVal;
  }

  private static int getSmallerGcdPair(int xRatio, int yRatio, int largeResult) {
    final int largeRatio = Math.max(xRatio, yRatio);
    final int smallRatio = Math.min(xRatio, yRatio);

    return largeResult / largeRatio * smallRatio;
  }
}

Comparez le code

Puisqu'il s'agit d'un code simple, je pense que vous pouvez le lire sans vous en rendre compte même dans une langue avec laquelle vous n'êtes généralement pas impliqué. Il y a certainement des bizarreries dans l'écriture pour chaque langue, mais à l'inverse, la différence semble être autant.


Résumé

--Il existe des cas où le rapport exact ne peut être obtenu par simple division. --Le rapport entier peut être calculé en utilisant le nombre d'engagement maximum.


prime

Seulement Kotlin, mais j'écrirai une manière récursive d'écrire qui donne le maximum d'engagement.

gcd(Math.max(x, y), Math.min(x, y))
tailrec fun gcd(largeInput: Int, smallInput: Int): Int 
  = if(smallInput == 0) largeInput else gcd(smallInput, largeInput % smallInput)

Recommended Posts

Une histoire sur la rédaction d'un calcul de ratio lors d'une session d'étude en interne
Une histoire sur l'écriture d'une méthode de dichotomie lors d'une session d'étude en interne
Une histoire sur la façon dont le comportement des jeunes s'est amélioré de manière surprenante lors d'une séance d'étude de 15 minutes tous les matins
Une histoire sur la façon dont le comportement des jeunes s'est amélioré de manière surprenante lors d'une séance d'étude de 15 minutes tous les matins
Une histoire sur la rédaction d'un calcul de ratio lors d'une session d'étude en interne
Une histoire sur l'écriture d'une méthode de dichotomie lors d'une session d'étude en interne
L'histoire de la participation à la session d'étude Docker + k8s [JAZUG Women's Club x Java Women's Club]
L'histoire de la participation à la session d'étude Docker + k8s [JAZUG Women's Club x Java Women's Club]
[Session d'étude interne] Gestion des exceptions Java (2017/04/26)
Notes d'étude pour obtenir un emploi dans une entreprise informatique par des personnes inexpérimentées
L'histoire de la rencontre d'un débordement arithmétique qui ne devrait pas être rencontré dans Ruby