package com.ssynhtn.medium

class Permutations {
    var swapCount = 0;
    fun permute(nums: IntArray): List<List<Int>> {
        val collect = mutableListOf<List<Int>>()
        permute(nums, 0, collect)
        return collect
    }

    fun permute2(nums: IntArray): List<List<Int>> {
        val collect = mutableListOf<List<Int>>()

        swapPermute2(nums, nums.size, collect)

        return collect
    }

    /**
     * 将最后size个进行permute, 结果添加到collect, 并且使得最后size个的顺序与输入相比为倒序
     * pre: size >= 1
     */
    fun swapPermute2(nums: IntArray, size: Int, collect: MutableList<List<Int>>) {
        if (size == 1) {
            collect.add(nums.toList())
            return
        }

        swapPermute2(nums, size - 1, collect)
        val index = size - 1
        var j = 0;
        var i = index - 2

        while (j < index) {
            if (j < index) {
                val temp = nums[index]
                nums[index] = nums[j]
                nums[j] = temp
                swapPermute2(nums, size - 1, collect)
                j += 2;
            }

            if (i >= 0) {
                val temp = nums[i]
                nums[i] = nums[index]
                nums[index] = temp
                swapPermute2(nums, size - 1, collect)
                i -= 2;
            }

        }

        if (j == size) {
            reverse(nums, 0, index - 1)
        }

    }

    private fun reverse(nums: IntArray, i: Int, j: Int) {
        var start = i
        var end = j
        while (start < end) {
            val temp = nums[start]
            nums[start] = nums[end]
            nums[end] = temp
            start++;
            end--;
        }
    }

    fun permute(nums: IntArray, fixCount: Int, collect: MutableList<List<Int>>) {
        if (fixCount >= nums.size - 1) {
            collect.add(nums.toList())
            return
        }

        permute(nums, fixCount + 1, collect)

        for (i in fixCount + 1 until nums.size) {
            val temp = nums[fixCount]
            nums[fixCount] = nums[i]
            nums[i] = temp
            permute(nums, fixCount + 1, collect)
            nums[i] = nums[fixCount]
            nums[fixCount] = temp
            swapCount += 2
        }
    }
}

fun main(args: Array<String>) {
    val nums = intArrayOf(1,2,3)
    val nums2 = nums.clone()

    val perm = Permutations()
    val perm2 = Permutations()

//    val ps = perm.permute(nums)
    val ps2 = perm2.permute2(nums)

//    println(ps)
//    println(nums.toList())
    println("swap count " + perm.swapCount)

    println("==2== ")
    println(ps2)
//    println(nums2.toList())
    println("swap count2 " + perm2.swapCount)

}

Compiled from "Permutations.kt"
public final class com.ssynhtn.medium.Permutations {
  private int swapCount;

  public com.ssynhtn.medium.Permutations();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public final int getSwapCount();
    Code:
       0: aload_0
       1: getfield      #16                 // Field swapCount:I
       4: ireturn

  public final void setSwapCount(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #16                 // Field swapCount:I
       5: return

  public final java.util.List<java.util.List<java.lang.Integer>> permute(int[]);
    Code:
       0: aload_1
       1: ldc           #25                 // String nums
       3: invokestatic  #31                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #33                 // class java/util/ArrayList
       9: dup
      10: invokespecial #34                 // Method java/util/ArrayList."<init>":()V
      13: checkcast     #36                 // class java/util/List
      16: astore_2
      17: aload_0
      18: aload_1
      19: iconst_0
      20: aload_2
      21: invokevirtual #39                 // Method permute:([IILjava/util/List;)V
      24: aload_2
      25: areturn

  public final java.util.List<java.util.List<java.lang.Integer>> permute2(int[]);
    Code:
       0: aload_1
       1: ldc           #25                 // String nums
       3: invokestatic  #31                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #33                 // class java/util/ArrayList
       9: dup
      10: invokespecial #34                 // Method java/util/ArrayList."<init>":()V
      13: checkcast     #36                 // class java/util/List
      16: astore_2
      17: aload_0
      18: aload_1
      19: aload_1
      20: arraylength
      21: aload_2
      22: invokevirtual #46                 // Method swapPermute2:([IILjava/util/List;)V
      25: aload_2
      26: areturn

  public final void swapPermute2(int[], int, java.util.List<java.util.List<java.lang.Integer>>);
    Code:
       0: aload_1
       1: ldc           #25                 // String nums
       3: invokestatic  #31                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_3
       7: ldc           #48                 // String collect
       9: invokestatic  #31                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: iload_2
      13: iconst_1
      14: if_icmpne     29
      17: aload_3
      18: aload_1
      19: invokestatic  #53                 // Method kotlin/collections/ArraysKt.toList:([I)Ljava/util/List;
      22: invokeinterface #57,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      27: pop
      28: return
      29: aload_0
      30: aload_1
      31: iload_2
      32: iconst_1
      33: isub
      34: aload_3
      35: invokevirtual #46                 // Method swapPermute2:([IILjava/util/List;)V
      38: iload_2
      39: iconst_1
      40: isub
      41: istore        4
      43: iconst_0
      44: istore        5
      46: iload         4
      48: iconst_2
      49: isub
      50: istore        6
      52: iload         5
      54: iload         4
      56: if_icmpge     138
      59: iload         5
      61: iload         4
      63: if_icmpge     98
      66: aload_1
      67: iload         4
      69: iaload
      70: istore        7
      72: aload_1
      73: iload         4
      75: aload_1
      76: iload         5
      78: iaload
      79: iastore
      80: aload_1
      81: iload         5
      83: iload         7
      85: iastore
      86: aload_0
      87: aload_1
      88: iload_2
      89: iconst_1
      90: isub
      91: aload_3
      92: invokevirtual #46                 // Method swapPermute2:([IILjava/util/List;)V
      95: iinc          5, 2
      98: iload         6
     100: iflt          52
     103: aload_1
     104: iload         6
     106: iaload
     107: istore        7
     109: aload_1
     110: iload         6
     112: aload_1
     113: iload         4
     115: iaload
     116: iastore
     117: aload_1
     118: iload         4
     120: iload         7
     122: iastore
     123: aload_0
     124: aload_1
     125: iload_2
     126: iconst_1
     127: isub
     128: aload_3
     129: invokevirtual #46                 // Method swapPermute2:([IILjava/util/List;)V
     132: iinc          6, -2
     135: goto          52
     138: iload         5
     140: iload_2
     141: if_icmpne     154
     144: aload_0
     145: aload_1
     146: iconst_0
     147: iload         4
     149: iconst_1
     150: isub
     151: invokespecial #61                 // Method reverse:([III)V
     154: return

  private final void reverse(int[], int, int);
    Code:
       0: iload_2
       1: istore        4
       3: iload_3
       4: istore        5
       6: iload         4
       8: iload         5
      10: if_icmpge     42
      13: aload_1
      14: iload         4
      16: iaload
      17: istore        6
      19: aload_1
      20: iload         4
      22: aload_1
      23: iload         5
      25: iaload
      26: iastore
      27: aload_1
      28: iload         5
      30: iload         6
      32: iastore
      33: iinc          4, 1
      36: iinc          5, -1
      39: goto          6
      42: return

  public final void permute(int[], int, java.util.List<java.util.List<java.lang.Integer>>);
    Code:
       0: aload_1
       1: ldc           #25                 // String nums
       3: invokestatic  #31                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_3
       7: ldc           #48                 // String collect
       9: invokestatic  #31                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: iload_2
      13: aload_1
      14: arraylength
      15: iconst_1
      16: isub
      17: if_icmplt     32
      20: aload_3
      21: aload_1
      22: invokestatic  #53                 // Method kotlin/collections/ArraysKt.toList:([I)Ljava/util/List;
      25: invokeinterface #57,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      30: pop
      31: return
      32: aload_0
      33: aload_1
      34: iload_2
      35: iconst_1
      36: iadd
      37: aload_3
      38: invokevirtual #39                 // Method permute:([IILjava/util/List;)V
      41: iload_2
      42: iconst_1
      43: iadd
      44: istore        4
      46: aload_1
      47: arraylength
      48: istore        5
      50: iload         4
      52: iload         5
      54: if_icmpge     112
      57: aload_1
      58: iload_2
      59: iaload
      60: istore        6
      62: aload_1
      63: iload_2
      64: aload_1
      65: iload         4
      67: iaload
      68: iastore
      69: aload_1
      70: iload         4
      72: iload         6
      74: iastore
      75: aload_0
      76: aload_1
      77: iload_2
      78: iconst_1
      79: iadd
      80: aload_3
      81: invokevirtual #39                 // Method permute:([IILjava/util/List;)V
      84: aload_1
      85: iload         4
      87: aload_1
      88: iload_2
      89: iaload
      90: iastore
      91: aload_1
      92: iload_2
      93: iload         6
      95: iastore
      96: aload_0
      97: aload_0
      98: getfield      #16                 // Field swapCount:I
     101: iconst_2
     102: iadd
     103: putfield      #16                 // Field swapCount:I
     106: iinc          4, 1
     109: goto          50
     112: return
}

Compiled from "Permutations.kt"
public final class com.ssynhtn.medium.PermutationsKt {
  public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #9                  // String args
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: iconst_3
       7: newarray       int
       9: astore_2
      10: aload_2
      11: iconst_0
      12: iconst_1
      13: iastore
      14: aload_2
      15: iconst_1
      16: iconst_2
      17: iastore
      18: aload_2
      19: iconst_2
      20: iconst_3
      21: iastore
      22: aload_2
      23: astore_1
      24: aload_1
      25: invokevirtual #19                 // Method java/lang/Object.clone:()Ljava/lang/Object;
      28: checkcast     #21                 // class "[I"
      31: astore_2
      32: new           #23                 // class com/ssynhtn/medium/Permutations
      35: dup
      36: invokespecial #27                 // Method com/ssynhtn/medium/Permutations."<init>":()V
      39: astore_3
      40: new           #23                 // class com/ssynhtn/medium/Permutations
      43: dup
      44: invokespecial #27                 // Method com/ssynhtn/medium/Permutations."<init>":()V
      47: astore        4
      49: aload         4
      51: aload_1
      52: invokevirtual #31                 // Method com/ssynhtn/medium/Permutations.permute2:([I)Ljava/util/List;
      55: astore        5
      57: new           #33                 // class java/lang/StringBuilder
      60: dup
      61: invokespecial #34                 // Method java/lang/StringBuilder."<init>":()V
      64: ldc           #36                 // String swap count
      66: invokevirtual #40                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      69: aload_3
      70: invokevirtual #44                 // Method com/ssynhtn/medium/Permutations.getSwapCount:()I
      73: invokevirtual #47                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      76: invokevirtual #51                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      79: getstatic     #57                 // Field java/lang/System.out:Ljava/io/PrintStream;
      82: swap
      83: invokevirtual #63                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      86: ldc           #65                 // String ==2==
      88: getstatic     #57                 // Field java/lang/System.out:Ljava/io/PrintStream;
      91: swap
      92: invokevirtual #63                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      95: getstatic     #57                 // Field java/lang/System.out:Ljava/io/PrintStream;
      98: aload         5
     100: invokevirtual #63                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     103: new           #33                 // class java/lang/StringBuilder
     106: dup
     107: invokespecial #34                 // Method java/lang/StringBuilder."<init>":()V
     110: ldc           #67                 // String swap count2
     112: invokevirtual #40                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     115: aload         4
     117: invokevirtual #44                 // Method com/ssynhtn/medium/Permutations.getSwapCount:()I
     120: invokevirtual #47                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
     123: invokevirtual #51                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     126: getstatic     #57                 // Field java/lang/System.out:Ljava/io/PrintStream;
     129: swap
     130: invokevirtual #63                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     133: return
}


package com.github.ezauton.core.utils.math

/**
 * @param map
 * @return If is odd function
 */
fun hasOddSymmetry(map: Map<out Double, Double>): Boolean {
  return map.entries.stream().allMatch { entry ->
    val key = entry.key
    val value = entry.value
    val symmetricEntry = map[-key]?.toDouble()
    symmetricEntry != null && symmetricEntry == -value
  }
}

/**
 * @param map
 * @return If is even function
 */
fun hasEvenSymmetry(map: Map<out Double, Double>): Boolean {
  return map.entries.stream().allMatch { entry ->
    val key = entry.key
    val value = entry.value
    val symmetricValue = map[-key]?.toDouble()
    symmetricValue != null && symmetricValue == value
  }
}

/**
 * Solve for the roots of a quadratic of the form ax^2 + bx + c
 *
 * @param a x^2 coefficient
 * @param b x coefficient
 * @param c added constant
 * @return roots of the quadratic
 */
fun quadratic(a: Double, b: Double, c: Double): Set<Double> {
  val toReturn = HashSet<Double>()
  val discriminate = discriminate(a, b, c)
  if (discriminate < 0) {
    return toReturn
  } else if (discriminate == 0.0) {
    toReturn.add(-b / (2 * a))
  } else {
    val LHS = -b / (2 * a)
    val RHS = Math.sqrt(discriminate) / (2 * a)
    toReturn.add(LHS + RHS)
    toReturn.add(LHS - RHS)
  }
  return toReturn
}

/**
 * Solve for the discriminant of a quadratic of the form ax^2 + bx + c
 *
 * @param a x^2 coefficient
 * @param b x coefficient
 * @param c added thing
 * @return roots of the quadratic
 * @see MathUtils.Algebra.quadratic
 */
fun discriminate(a: Double, b: Double, c: Double): Double {
  return b * b - 4.0 * a * c
}

Compiled from "AlgebraUtils.kt"
public final class com.github.ezauton.core.utils.math.AlgebraUtilsKt {
  public static final boolean hasOddSymmetry(java.util.Map<? extends java.lang.Double, java.lang.Double>);
    Code:
       0: aload_0
       1: ldc           #10                 // String map
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokeinterface #22,  1           // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set;
      12: invokeinterface #28,  1           // InterfaceMethod java/util/Set.stream:()Ljava/util/stream/Stream;
      17: aload_0
      18: invokedynamic #48,  0             // InvokeDynamic #0:invoke:(Ljava/util/Map;)Lkotlin/jvm/functions/Function1;
      23: invokedynamic #59,  0             // InvokeDynamic #1:test:(Lkotlin/jvm/functions/Function1;)Ljava/util/function/Predicate;
      28: invokeinterface #65,  2           // InterfaceMethod java/util/stream/Stream.allMatch:(Ljava/util/function/Predicate;)Z
      33: ireturn

  public static final boolean hasEvenSymmetry(java.util.Map<? extends java.lang.Double, java.lang.Double>);
    Code:
       0: aload_0
       1: ldc           #10                 // String map
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokeinterface #22,  1           // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set;
      12: invokeinterface #28,  1           // InterfaceMethod java/util/Set.stream:()Ljava/util/stream/Stream;
      17: aload_0
      18: invokedynamic #72,  0             // InvokeDynamic #2:invoke:(Ljava/util/Map;)Lkotlin/jvm/functions/Function1;
      23: invokedynamic #77,  0             // InvokeDynamic #3:test:(Lkotlin/jvm/functions/Function1;)Ljava/util/function/Predicate;
      28: invokeinterface #65,  2           // InterfaceMethod java/util/stream/Stream.allMatch:(Ljava/util/function/Predicate;)Z
      33: ireturn

  public static final java.util.Set<java.lang.Double> quadratic(double, double, double);
    Code:
       0: new           #82                 // class java/util/HashSet
       3: dup
       4: invokespecial #86                 // Method java/util/HashSet."<init>":()V
       7: astore        6
       9: dload_0
      10: dload_2
      11: dload         4
      13: invokestatic  #90                 // Method discriminate:(DDD)D
      16: dstore        7
      18: dload         7
      20: dconst_0
      21: dcmpg
      22: ifge          31
      25: aload         6
      27: checkcast     #24                 // class java/util/Set
      30: areturn
      31: dload         7
      33: dconst_0
      34: dcmpg
      35: ifne          42
      38: iconst_1
      39: goto          43
      42: iconst_0
      43: ifeq          64
      46: aload         6
      48: dload_2
      49: dneg
      50: iconst_2
      51: i2d
      52: dload_0
      53: dmul
      54: ddiv
      55: invokestatic  #96                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      58: invokevirtual #99                 // Method java/util/HashSet.add:(Ljava/lang/Object;)Z
      61: goto          112
      64: dload_2
      65: dneg
      66: iconst_2
      67: i2d
      68: dload_0
      69: dmul
      70: ddiv
      71: dstore        9
      73: dload         7
      75: invokestatic  #105                // Method java/lang/Math.sqrt:(D)D
      78: iconst_2
      79: i2d
      80: dload_0
      81: dmul
      82: ddiv
      83: dstore        11
      85: aload         6
      87: dload         9
      89: dload         11
      91: dadd
      92: invokestatic  #96                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      95: invokevirtual #99                 // Method java/util/HashSet.add:(Ljava/lang/Object;)Z
      98: pop
      99: aload         6
     101: dload         9
     103: dload         11
     105: dsub
     106: invokestatic  #96                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
     109: invokevirtual #99                 // Method java/util/HashSet.add:(Ljava/lang/Object;)Z
     112: pop
     113: aload         6
     115: checkcast     #24                 // class java/util/Set
     118: areturn

  public static final double discriminate(double, double, double);
    Code:
       0: dload_2
       1: dload_2
       2: dmul
       3: ldc2_w        #114                // double 4.0d
       6: dload_0
       7: dmul
       8: dload         4
      10: dmul
      11: dsub
      12: dreturn

  private static final boolean hasOddSymmetry$lambda$0(java.util.Map, java.util.Map$Entry);
    Code:
       0: aload_1
       1: invokeinterface #121,  1          // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object;
       6: checkcast     #123                // class java/lang/Number
       9: invokevirtual #127                // Method java/lang/Number.doubleValue:()D
      12: dstore_2
      13: aload_1
      14: invokeinterface #130,  1          // InterfaceMethod java/util/Map$Entry.getValue:()Ljava/lang/Object;
      19: checkcast     #123                // class java/lang/Number
      22: invokevirtual #127                // Method java/lang/Number.doubleValue:()D
      25: dstore        4
      27: aload_0
      28: dload_2
      29: dneg
      30: invokestatic  #96                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      33: invokeinterface #133,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
      38: checkcast     #92                 // class java/lang/Double
      41: dup
      42: ifnull        54
      45: invokevirtual #134                // Method java/lang/Double.doubleValue:()D
      48: invokestatic  #96                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      51: goto          56
      54: pop
      55: aconst_null
      56: astore        6
      58: aload         6
      60: ifnull        78
      63: aload         6
      65: dload         4
      67: dneg
      68: invokestatic  #138                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Double;D)Z
      71: ifeq          78
      74: iconst_1
      75: goto          79
      78: iconst_0
      79: ireturn

  private static final boolean hasOddSymmetry$lambda$1(kotlin.jvm.functions.Function1, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokeinterface #149,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
       7: checkcast     #151                // class java/lang/Boolean
      10: invokevirtual #155                // Method java/lang/Boolean.booleanValue:()Z
      13: ireturn

  private static final boolean hasEvenSymmetry$lambda$2(java.util.Map, java.util.Map$Entry);
    Code:
       0: aload_1
       1: invokeinterface #121,  1          // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object;
       6: checkcast     #123                // class java/lang/Number
       9: invokevirtual #127                // Method java/lang/Number.doubleValue:()D
      12: dstore_2
      13: aload_1
      14: invokeinterface #130,  1          // InterfaceMethod java/util/Map$Entry.getValue:()Ljava/lang/Object;
      19: checkcast     #123                // class java/lang/Number
      22: invokevirtual #127                // Method java/lang/Number.doubleValue:()D
      25: dstore        4
      27: aload_0
      28: dload_2
      29: dneg
      30: invokestatic  #96                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      33: invokeinterface #133,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
      38: checkcast     #92                 // class java/lang/Double
      41: dup
      42: ifnull        54
      45: invokevirtual #134                // Method java/lang/Double.doubleValue:()D
      48: invokestatic  #96                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      51: goto          56
      54: pop
      55: aconst_null
      56: astore        6
      58: aload         6
      60: ifnull        77
      63: aload         6
      65: dload         4
      67: invokestatic  #138                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Double;D)Z
      70: ifeq          77
      73: iconst_1
      74: goto          78
      77: iconst_0
      78: ireturn

  private static final boolean hasEvenSymmetry$lambda$3(kotlin.jvm.functions.Function1, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokeinterface #149,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
       7: checkcast     #151                // class java/lang/Boolean
      10: invokevirtual #155                // Method java/lang/Boolean.booleanValue:()Z
      13: ireturn
}


package o9referenzdatentypen

/**
 * Programmieren Trainieren Seite 192
 * W.9.2 <NAME>
 *
 * Erweitert um [Fraction.divide] und weitere helper wie [Fraction.shorten] und [Fraction.gcd]
 * */

fun main() {
    val a = Fraction(numerator = 1, denominator = 2)
    val b = Fraction(numerator = 1, denominator = 4)
    val f = Fraction(numerator = 8, denominator = 4)

    val c = a.add(b)
    val d = a.multiply(b)
    println(c.toString())
    println(d.toString())
    println(f)
    println(b.divide(a))
}

/**
 * Represents a fraction with a numerator and a denominator.
 *
 * @property numerator The numerator of the fraction.
 * @property denominator The denominator of the fraction.
 */
data class Fraction(
    private val numerator: Int,
    private val denominator: Int
) {

    /**
     * Adds [other] to this fraction and returns the result as a new fraction.
     *
     * @param other The fraction to add to this fraction.
     * @return A new fraction that is the sum of this fraction and [other].
     */
    fun add(other: Fraction): Fraction {
        val newNumerator = (this.numerator * other.denominator) + (other.numerator * this.denominator)
        val newDominator = this.denominator * other.denominator
        return this.copy(numerator = newNumerator, denominator = newDominator).shorten()
    }

    /**
     * Multiplies this fraction by [other] and returns the result as a new fraction.
     *
     * @param other The fraction to multiply with this fraction.
     * @return A new fraction that is the product of this fraction and [other].
     */
    fun multiply(other: Fraction): Fraction {
        val newNumerator = this.numerator * other.numerator
        val newDominator = this.denominator * other.denominator
        return this.copy(numerator = newNumerator, denominator = newDominator).shorten()
    }

    /**
     * Divides this fraction by [other] and returns the result as a new fraction.
     *
     * @param other The fraction to divide this fraction by.
     * @return A new fraction that is the quotient of this fraction divided by [other].
     */
    fun divide(other: Fraction) : Fraction {
        return this.multiply(other.copy(numerator = other.denominator, denominator = other.numerator))
    }

    /**
     * Returns a new fraction that is a simplified version of this fraction.
     *
     * @return A new fraction that has the same value as this fraction but with the numerator and denominator
     * divided by their greatest common divisor.
     */
    private fun shorten(): Fraction {
        val gcd = gcd()
        return this.copy(numerator = this.numerator / gcd, denominator = this.denominator / gcd)
    }

    /**
     * Calculates and returns the greatest common divisor (GCD) of the numerator and denominator of this Fraction.
     * This function uses the Euclidean algorithm to calculate the GCD.
     *
     * @return the GCD of the numerator and denominator of this Fraction.
     */
    private fun gcd(): Int {
        var num1 = this.numerator
        var num2 = this.denominator
        while (num2 != 0) {
            val remainder = num1 % num2
            num1 = num2
            num2 = remainder
        }
        return num1
    }

    /**
     * Returns a string representation of this fraction.
     *
     * If the denominator of the fraction is 1, only the numerator is returned. Otherwise,
     * the string representation of the numerator and denominator is returned.
     *
     * @return A string representation of this fraction.
     */
    override fun toString(): String {
        val gcd = gcd()
        val copy = this.copy(numerator = this.numerator / gcd, denominator = this.denominator / gcd)
        return if (copy.denominator == 1) {
            "${copy.numerator}"
        } else "${copy.numerator}/${copy.denominator}"
    }
}

Compiled from "Fraction.kt"
public final class o9referenzdatentypen.Fraction {
  private final int numerator;

  private final int denominator;

  public o9referenzdatentypen.Fraction(int, int);
    Code:
       0: aload_0
       1: invokespecial #9                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iload_1
       6: putfield      #13                 // Field numerator:I
       9: aload_0
      10: iload_2
      11: putfield      #16                 // Field denominator:I
      14: return

  public final o9referenzdatentypen.Fraction add(o9referenzdatentypen.Fraction);
    Code:
       0: aload_1
       1: ldc           #23                 // String other
       3: invokestatic  #29                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: getfield      #13                 // Field numerator:I
      10: aload_1
      11: getfield      #16                 // Field denominator:I
      14: imul
      15: aload_1
      16: getfield      #13                 // Field numerator:I
      19: aload_0
      20: getfield      #16                 // Field denominator:I
      23: imul
      24: iadd
      25: istore_2
      26: aload_0
      27: getfield      #16                 // Field denominator:I
      30: aload_1
      31: getfield      #16                 // Field denominator:I
      34: imul
      35: istore_3
      36: aload_0
      37: iload_2
      38: iload_3
      39: invokevirtual #33                 // Method copy:(II)Lo9referenzdatentypen/Fraction;
      42: invokespecial #37                 // Method shorten:()Lo9referenzdatentypen/Fraction;
      45: areturn

  public final o9referenzdatentypen.Fraction multiply(o9referenzdatentypen.Fraction);
    Code:
       0: aload_1
       1: ldc           #23                 // String other
       3: invokestatic  #29                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: getfield      #13                 // Field numerator:I
      10: aload_1
      11: getfield      #13                 // Field numerator:I
      14: imul
      15: istore_2
      16: aload_0
      17: getfield      #16                 // Field denominator:I
      20: aload_1
      21: getfield      #16                 // Field denominator:I
      24: imul
      25: istore_3
      26: aload_0
      27: iload_2
      28: iload_3
      29: invokevirtual #33                 // Method copy:(II)Lo9referenzdatentypen/Fraction;
      32: invokespecial #37                 // Method shorten:()Lo9referenzdatentypen/Fraction;
      35: areturn

  public final o9referenzdatentypen.Fraction divide(o9referenzdatentypen.Fraction);
    Code:
       0: aload_1
       1: ldc           #23                 // String other
       3: invokestatic  #29                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_1
       8: aload_1
       9: getfield      #16                 // Field denominator:I
      12: aload_1
      13: getfield      #13                 // Field numerator:I
      16: invokevirtual #33                 // Method copy:(II)Lo9referenzdatentypen/Fraction;
      19: invokevirtual #43                 // Method multiply:(Lo9referenzdatentypen/Fraction;)Lo9referenzdatentypen/Fraction;
      22: areturn

  private final o9referenzdatentypen.Fraction shorten();
    Code:
       0: aload_0
       1: invokespecial #47                 // Method gcd:()I
       4: istore_1
       5: aload_0
       6: aload_0
       7: getfield      #13                 // Field numerator:I
      10: iload_1
      11: idiv
      12: aload_0
      13: getfield      #16                 // Field denominator:I
      16: iload_1
      17: idiv
      18: invokevirtual #33                 // Method copy:(II)Lo9referenzdatentypen/Fraction;
      21: areturn

  private final int gcd();
    Code:
       0: aload_0
       1: getfield      #13                 // Field numerator:I
       4: istore_1
       5: aload_0
       6: getfield      #16                 // Field denominator:I
       9: istore_2
      10: iload_2
      11: ifeq          25
      14: iload_1
      15: iload_2
      16: irem
      17: istore_3
      18: iload_2
      19: istore_1
      20: iload_3
      21: istore_2
      22: goto          10
      25: iload_1
      26: ireturn

  public java.lang.String toString();
    Code:
       0: aload_0
       1: invokespecial #47                 // Method gcd:()I
       4: istore_1
       5: aload_0
       6: aload_0
       7: getfield      #13                 // Field numerator:I
      10: iload_1
      11: idiv
      12: aload_0
      13: getfield      #16                 // Field denominator:I
      16: iload_1
      17: idiv
      18: invokevirtual #33                 // Method copy:(II)Lo9referenzdatentypen/Fraction;
      21: astore_2
      22: aload_2
      23: getfield      #16                 // Field denominator:I
      26: iconst_1
      27: if_icmpne     40
      30: aload_2
      31: getfield      #13                 // Field numerator:I
      34: invokestatic  #58                 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
      37: goto          69
      40: new           #60                 // class java/lang/StringBuilder
      43: dup
      44: invokespecial #61                 // Method java/lang/StringBuilder."<init>":()V
      47: aload_2
      48: getfield      #13                 // Field numerator:I
      51: invokevirtual #65                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      54: bipush        47
      56: invokevirtual #68                 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      59: aload_2
      60: getfield      #16                 // Field denominator:I
      63: invokevirtual #65                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      66: invokevirtual #70                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      69: areturn

  private final int component1();
    Code:
       0: aload_0
       1: getfield      #13                 // Field numerator:I
       4: ireturn

  private final int component2();
    Code:
       0: aload_0
       1: getfield      #16                 // Field denominator:I
       4: ireturn

  public final o9referenzdatentypen.Fraction copy(int, int);
    Code:
       0: new           #2                  // class o9referenzdatentypen/Fraction
       3: dup
       4: iload_1
       5: iload_2
       6: invokespecial #74                 // Method "<init>":(II)V
       9: areturn

  public static o9referenzdatentypen.Fraction copy$default(o9referenzdatentypen.Fraction, int, int, int, java.lang.Object);
    Code:
       0: iload_3
       1: iconst_1
       2: iand
       3: ifeq          11
       6: aload_0
       7: getfield      #13                 // Field numerator:I
      10: istore_1
      11: iload_3
      12: iconst_2
      13: iand
      14: ifeq          22
      17: aload_0
      18: getfield      #16                 // Field denominator:I
      21: istore_2
      22: aload_0
      23: iload_1
      24: iload_2
      25: invokevirtual #33                 // Method copy:(II)Lo9referenzdatentypen/Fraction;
      28: areturn

  public int hashCode();
    Code:
       0: aload_0
       1: getfield      #13                 // Field numerator:I
       4: invokestatic  #82                 // Method java/lang/Integer.hashCode:(I)I
       7: istore_1
       8: iload_1
       9: bipush        31
      11: imul
      12: aload_0
      13: getfield      #16                 // Field denominator:I
      16: invokestatic  #82                 // Method java/lang/Integer.hashCode:(I)I
      19: iadd
      20: istore_1
      21: iload_1
      22: ireturn

  public boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: if_acmpne     7
       5: iconst_1
       6: ireturn
       7: aload_1
       8: instanceof    #2                  // class o9referenzdatentypen/Fraction
      11: ifne          16
      14: iconst_0
      15: ireturn
      16: aload_1
      17: checkcast     #2                  // class o9referenzdatentypen/Fraction
      20: astore_2
      21: aload_0
      22: getfield      #13                 // Field numerator:I
      25: aload_2
      26: getfield      #13                 // Field numerator:I
      29: if_icmpeq     34
      32: iconst_0
      33: ireturn
      34: aload_0
      35: getfield      #16                 // Field denominator:I
      38: aload_2
      39: getfield      #16                 // Field denominator:I
      42: if_icmpeq     47
      45: iconst_0
      46: ireturn
      47: iconst_1
      48: ireturn
}

Compiled from "Fraction.kt"
public final class o9referenzdatentypen.FractionKt {
  public static final void main();
    Code:
       0: new           #8                  // class o9referenzdatentypen/Fraction
       3: dup
       4: iconst_1
       5: iconst_2
       6: invokespecial #12                 // Method o9referenzdatentypen/Fraction."<init>":(II)V
       9: astore_0
      10: new           #8                  // class o9referenzdatentypen/Fraction
      13: dup
      14: iconst_1
      15: iconst_4
      16: invokespecial #12                 // Method o9referenzdatentypen/Fraction."<init>":(II)V
      19: astore_1
      20: new           #8                  // class o9referenzdatentypen/Fraction
      23: dup
      24: bipush        8
      26: iconst_4
      27: invokespecial #12                 // Method o9referenzdatentypen/Fraction."<init>":(II)V
      30: astore_2
      31: aload_0
      32: aload_1
      33: invokevirtual #16                 // Method o9referenzdatentypen/Fraction.add:(Lo9referenzdatentypen/Fraction;)Lo9referenzdatentypen/Fraction;
      36: astore_3
      37: aload_0
      38: aload_1
      39: invokevirtual #19                 // Method o9referenzdatentypen/Fraction.multiply:(Lo9referenzdatentypen/Fraction;)Lo9referenzdatentypen/Fraction;
      42: astore        4
      44: aload_3
      45: invokevirtual #23                 // Method o9referenzdatentypen/Fraction.toString:()Ljava/lang/String;
      48: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      51: swap
      52: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      55: aload         4
      57: invokevirtual #23                 // Method o9referenzdatentypen/Fraction.toString:()Ljava/lang/String;
      60: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      63: swap
      64: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      67: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      70: aload_2
      71: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      74: aload_1
      75: aload_0
      76: invokevirtual #38                 // Method o9referenzdatentypen/Fraction.divide:(Lo9referenzdatentypen/Fraction;)Lo9referenzdatentypen/Fraction;
      79: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      82: swap
      83: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      86: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #47                 // Method main:()V
       3: return
}