KMP 实现鸿蒙跨端:Kotlin 斐波那契数列计算器

目录

  1. 概述
  2. 工具功能
  3. 核心实现
  4. 实战案例
  5. 编译过程详解
  6. 工具扩展
  7. 最佳实践
  8. 常见问题

概述

本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的斐波那契数列计算器系统。这个案例展示了如何使用 Kotlin 的数学计算、集合操作和算法实现来创建一个功能丰富的数列分析工具。通过 KMP,这个工具可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,并支持用户输入进行实时处理。

工具的特点

  • 数列生成:快速生成指定长度的斐波那契数列
  • 多维度分析:从多个角度分析数列特性
  • 数学计算:计算统计值、比率、增长率等
  • 质数识别:识别数列中的质数
  • 黄金比例:展示黄金比例的数学美妙
  • 跨端兼容:一份 Kotlin 代码可同时服务多个平台

工具功能

1. 数列生成

  • 项数范围:支持 1-50 项
  • 数列显示:完整显示生成的斐波那契数列
  • 性能优化:使用高效的迭代算法

2. 基础统计

  • 总和:计算数列中所有数字的和
  • 平均值:计算数列的平均值
  • 最大值:找出数列中的最大值
  • 最小值:找出数列中的最小值

3. 奇偶分析

  • 偶数个数:统计偶数的个数
  • 奇数个数:统计奇数的个数
  • 奇偶分布:展示奇偶数的分布规律

4. 质数分析

  • 质数识别:识别数列中的所有质数
  • 质数列表:显示所有质数
  • 质数个数:统计质数的个数

5. 黄金比例分析

  • 相邻比率:计算相邻项的比率
  • 平均比率:计算所有比率的平均值
  • 理论值对比:与黄金比例 1.618034 对比
  • 比率列表:显示前 5 个比率

6. 增长率分析

  • 增长率计算:计算相邻项的增长率
  • 平均增长率:计算平均增长率
  • 增长趋势:展示增长的加速趋势

核心实现

1. 斐波那契数列生成

val fibonacci = mutableListOf<Long>()
if (n >= 1) fibonacci.add(0)
if (n >= 2) fibonacci.add(1)

for (i in 2 until n) {
    fibonacci.add(fibonacci[i - 1] + fibonacci[i - 2])
}

2. 基础统计

val sum = fibonacci.sum()
val average = if (fibonacci.isNotEmpty()) sum / fibonacci.size else 0L
val max = fibonacci.maxOrNull() ?: 0L
val min = fibonacci.minOrNull() ?: 0L

3. 奇偶分析

val isEven = fibonacci.count { it % 2L == 0L }
val isOdd = fibonacci.count { it % 2L != 0L }

4. 质数检查

fun isPrime(n: Long): Boolean {
    if (n <= 1) return false
    if (n <= 3) return true
    if (n % 2 == 0L || n % 3 == 0L) return false
    
    var i = 5L
    while (i * i <= n) {
        if (n % i == 0L || n % (i + 2) == 0L) return false
        i += 6
    }
    return true
}

5. 黄金比例计算

val ratios = mutableListOf<Double>()
for (i in 1 until fibonacci.size) {
    if (fibonacci[i - 1] != 0L) {
        val ratio = fibonacci[i].toDouble() / fibonacci[i - 1].toDouble()
        ratios.add(ratio)
    }
}
val avgRatio = if (ratios.isNotEmpty()) ratios.sum() / ratios.size else 0.0

6. 增长率计算

val growthRates = mutableListOf<Double>()
for (i in 1 until fibonacci.size) {
    if (fibonacci[i - 1] != 0L) {
        val rate = ((fibonacci[i] - fibonacci[i - 1]).toDouble() / fibonacci[i - 1]) * 100
        growthRates.add(rate)
    }
}
val avgGrowthRate = if (growthRates.isNotEmpty()) growthRates.sum() / growthRates.size else 0.0

实战案例

案例:完整的斐波那契数列计算器

Kotlin 源代码
@OptIn(ExperimentalJsExport::class)
@JsExport
fun fibonacciCalculator(inputNumber: String = "10"): String {
    // 解析输入
    val n = inputNumber.trim().toIntOrNull() ?: 10
    
    if (n < 0) {
        return "❌ 错误: 输入必须是非负整数\n请输入 0 或更大的数字"
    }
    
    if (n > 50) {
        return "❌ 错误: 输入过大\n为了性能考虑,请输入不超过 50 的数字"
    }
    
    // 1. 生成斐波那契数列
    val fibonacci = mutableListOf<Long>()
    if (n >= 1) fibonacci.add(0)
    if (n >= 2) fibonacci.add(1)
    
    for (i in 2 until n) {
        fibonacci.add(fibonacci[i - 1] + fibonacci[i - 2])
    }
    
    // 2. 计算统计信息
    val sum = fibonacci.sum()
    val average = if (fibonacci.isNotEmpty()) sum / fibonacci.size else 0L
    val max = fibonacci.maxOrNull() ?: 0L
    val min = fibonacci.minOrNull() ?: 0L
    
    // 3. 分析数列性质
    val isEven = fibonacci.count { it % 2L == 0L }
    val isOdd = fibonacci.count { it % 2L != 0L }
    
    // 4. 计算相邻比率(黄金比例)
    val ratios = mutableListOf<Double>()
    for (i in 1 until fibonacci.size) {
        if (fibonacci[i - 1] != 0L) {
            val ratio = fibonacci[i].toDouble() / fibonacci[i - 1].toDouble()
            ratios.add(ratio)
        }
    }
    val avgRatio = if (ratios.isNotEmpty()) ratios.sum() / ratios.size else 0.0
    
    // 5. 找出特殊数字
    val primeNumbers = mutableListOf<Long>()
    for (num in fibonacci) {
        if (isPrime(num)) {
            primeNumbers.add(num)
        }
    }
    
    // 6. 计算增长率
    val growthRates = mutableListOf<Double>()
    for (i in 1 until fibonacci.size) {
        if (fibonacci[i - 1] != 0L) {
            val rate = ((fibonacci[i] - fibonacci[i - 1]).toDouble() / fibonacci[i - 1]) * 100
            growthRates.add(rate)
        }
    }
    val avgGrowthRate = if (growthRates.isNotEmpty()) growthRates.sum() / growthRates.size else 0.0
    
    // 7. 数列显示
    val fibonacciStr = fibonacci.joinToString(", ")
    
    // 8. 质数列表
    val primeStr = if (primeNumbers.isNotEmpty()) {
        primeNumbers.joinToString(", ")
    } else {
        "无"
    }
    
    // 9. 比率列表(取前5个)
    val ratioStr = ratios.take(5).mapIndexed { index, ratio ->
        "  ${index + 1}. F(${index + 2})/F(${index + 1}) = $ratio"
    }.joinToString("\n")
    
    return "🔢 斐波那契数列计算器\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "1️⃣ 数列信息:\n" +
           "  项数: $n\n" +
           "  数列: $fibonacciStr\n\n" +
           "2️⃣ 基础统计:\n" +
           "  总和: $sum\n" +
           "  平均值: $average\n" +
           "  最大值: $max\n" +
           "  最小值: $min\n\n" +
           "3️⃣ 奇偶分析:\n" +
           "  偶数个数: $isEven\n" +
           "  奇数个数: $isOdd\n\n" +
           "4️⃣ 质数分析:\n" +
           "  质数个数: ${primeNumbers.size}\n" +
           "  质数列表: $primeStr\n\n" +
           "5️⃣ 黄金比例分析:\n" +
           "  平均比率: $avgRatio\n" +
           "  理论值: 1.618034\n" +
           "  比率列表:\n" +
           ratioStr + "\n\n" +
           "6️⃣ 增长率分析:\n" +
           "  平均增长率: $avgGrowthRate%\n\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "✅ 计算完成!"
}

fun isPrime(n: Long): Boolean {
    if (n <= 1) return false
    if (n <= 3) return true
    if (n % 2 == 0L || n % 3 == 0L) return false
    
    var i = 5L
    while (i * i <= n) {
        if (n % i == 0L || n % (i + 2) == 0L) return false
        i += 6
    }
    return true
}
ArkTS 调用代码(带输入框)
import { fibonacciCalculator } from './hellokjs';

@Entry
@Component
struct Index {
  @State message: string = '加载中...';
  @State results: string[] = [];
  @State caseTitle: string = '斐波那契数列计算器';
  @State inputText: string = '10';

  aboutToAppear(): void {
    this.loadResults();
  }

  loadResults(): void {
    try {
      const results: string[] = [];
      const algorithmResult = fibonacciCalculator(this.inputText);
      results.push(algorithmResult);
      
      this.results = results;
      this.message = '✓ 计算完成';
    } catch (error) {
      this.message = `✗ 错误: ${error}`;
    }
  }

  build() {
    Column() {
      // 顶部标题栏
      Row() {
        Text('KMP 鸿蒙跨端')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
        Spacer()
        Text('Kotlin 案例')
          .fontSize(14)
          .fontColor(Color.White)
      }
      .width('100%')
      .height(50)
      .backgroundColor('#3b82f6')
      .padding({ left: 20, right: 20 })
      .alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.SpaceBetween)

      // 案例标题
      Column() {
        Text(this.caseTitle)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#1f2937')
        Text(this.message)
          .fontSize(13)
          .fontColor('#6b7280')
          .margin({ top: 5 })
      }
      .width('100%')
      .padding({ left: 20, right: 20, top: 20, bottom: 15 })
      .alignItems(HorizontalAlign.Start)

      // 输入框区域
      Column() {
        Text('输入项数 (1-50):')
          .fontSize(14)
          .fontWeight(FontWeight.Bold)
          .fontColor('#1f2937')
          .margin({ bottom: 8 })
        
        TextInput({ placeholder: '输入斐波那契数列的项数...', text: this.inputText })
          .width('100%')
          .height(60)
          .padding(12)
          .border({ width: 1, color: '#d1d5db' })
          .borderRadius(6)
          .onChange((value: string) => {
            this.inputText = value
          })
        
        Button('计算')
          .width('100%')
          .height(40)
          .margin({ top: 12 })
          .backgroundColor('#3b82f6')
          .fontColor(Color.White)
          .onClick(() => {
            this.loadResults()
          })
      }
      .width('100%')
      .padding({ left: 16, right: 16, bottom: 16 })

      // 结果显示区域
      Scroll() {
        Column() {
          ForEach(this.results, (result: string) => {
            Column() {
              Text(result)
                .fontSize(13)
                .fontFamily('monospace')
                .fontColor('#374151')
                .width('100%')
                .margin({ top: 10 })
            }
            .width('100%')
            .padding(16)
            .backgroundColor(Color.White)
            .border({ width: 1, color: '#e5e7eb' })
            .borderRadius(8)
            .margin({ bottom: 12 })
          })
        }
        .width('100%')
        .padding({ left: 16, right: 16 })
      }
      .layoutWeight(1)
      .width('100%')

      // 底部按钮区域
      Row() {
        Button('示例 (10)')
          .width('48%')
          .height(44)
          .backgroundColor('#10b981')
          .fontColor(Color.White)
          .fontSize(14)
          .onClick(() => {
            this.inputText = '10'
            this.loadResults()
          })

        Button('清空')
          .width('48%')
          .height(44)
          .backgroundColor('#6b7280')
          .fontColor(Color.White)
          .fontSize(14)
          .onClick(() => {
            this.inputText = ''
            this.results = []
          })
      }
      .width('100%')
      .padding({ left: 16, right: 16, bottom: 20 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#f9fafb')
  }
}

编译过程详解

Kotlin 到 JavaScript 的转换

Kotlin 特性 JavaScript 等价物
mutableListOf 数组 []
sum() reduce 或循环求和
count() filter().length
maxOrNull/minOrNull Math.max/min
toDouble() 类型转换
joinToString() join()

关键转换点

  1. 集合操作:转换为 JavaScript 数组操作
  2. 数学计算:转换为 JavaScript 数学运算
  3. 条件计数:转换为循环计数
  4. 字符串格式化:转换为模板字符串

工具扩展

扩展 1:添加卢卡斯数列

fun lucasSequence(n: Int): List<Long> {
    val lucas = mutableListOf<Long>()
    if (n >= 1) lucas.add(2)
    if (n >= 2) lucas.add(1)
    
    for (i in 2 until n) {
        lucas.add(lucas[i - 1] + lucas[i - 2])
    }
    return lucas
}

扩展 2:添加比布那奇数列

fun tribonacci(n: Int): List<Long> {
    val trib = mutableListOf<Long>()
    if (n >= 1) trib.add(0)
    if (n >= 2) trib.add(0)
    if (n >= 3) trib.add(1)
    
    for (i in 3 until n) {
        trib.add(trib[i - 1] + trib[i - 2] + trib[i - 3])
    }
    return trib
}

扩展 3:添加斐波那契数列的性质检查

fun isFibonacciNumber(num: Long): Boolean {
    var a = 0L
    var b = 1L
    
    while (a < num) {
        val temp = a + b
        a = b
        b = temp
    }
    return a == num
}

扩展 4:添加斐波那契数列的应用

fun fibonacciGCD(n: Int, m: Int): Long {
    // GCD(F(n), F(m)) = F(GCD(n, m))
    val fib = mutableListOf<Long>()
    // ... 生成斐波那契数列
    return fib[gcd(n, m)]
}

最佳实践

1. 使用 Long 而不是 Int

// ✅ 好:使用 Long 处理大数字
val fibonacci = mutableListOf<Long>()

// ❌ 不好:Int 会溢出
val fibonacci = mutableListOf<Int>()

2. 检查边界条件

// ✅ 好:检查输入范围
if (n < 0 || n > 50) {
    return "错误: 输入超出范围"
}

// ❌ 不好:不检查边界
val fib = generateFibonacci(n)

3. 避免重复计算

// ✅ 好:缓存计算结果
val fibonacci = mutableListOf<Long>()
for (i in 2 until n) {
    fibonacci.add(fibonacci[i - 1] + fibonacci[i - 2])
}

// ❌ 不好:递归重复计算
fun fib(n: Int): Long {
    return if (n <= 1) n.toLong() else fib(n - 1) + fib(n - 2)
}

4. 使用合适的数据结构

// ✅ 好:使用 List 存储数列
val fibonacci: List<Long> = generateFibonacci(n)

// ❌ 不好:使用数组导致大小固定
val fibonacci = LongArray(n)

5. 处理特殊情况

// ✅ 好:处理零除
if (fibonacci[i - 1] != 0L) {
    val ratio = fibonacci[i].toDouble() / fibonacci[i - 1].toDouble()
}

// ❌ 不好:不检查零
val ratio = fibonacci[i].toDouble() / fibonacci[i - 1].toDouble()

常见问题

Q1: 为什么使用 Long 而不是 Int?

A: 斐波那契数列增长非常快。第 50 项已经超过 Int 的最大值 (2^31 - 1)。使用 Long 可以支持更大的项数。

// F(50) = 12586269025,超过 Int.MAX_VALUE (2147483647)

Q2: 如何优化性能?

A: 使用迭代而不是递归,避免重复计算:

// ✅ 高效:O(n) 时间复杂度
for (i in 2 until n) {
    fibonacci.add(fibonacci[i - 1] + fibonacci[i - 2])
}

// ❌ 低效:O(2^n) 时间复杂度
fun fib(n: Int): Long = if (n <= 1) n.toLong() else fib(n - 1) + fib(n - 2)

Q3: 黄金比例为什么接近 1.618?

A: 这是斐波那契数列的数学性质。相邻项的比率随着项数增加而逐渐接近黄金比例 φ = (1 + √5) / 2 ≈ 1.618034。

Q4: 如何检查一个数是否是斐波那契数?

A: 一个数是斐波那契数当且仅当 5n² + 4 或 5n² - 4 是完全平方数:

fun isFibonacciNumber(num: Long): Boolean {
    fun isPerfectSquare(x: Long): Boolean {
        val sqrt = kotlin.math.sqrt(x.toDouble()).toLong()
        return sqrt * sqrt == x
    }
    
    return isPerfectSquare(5 * num * num + 4) || 
           isPerfectSquare(5 * num * num - 4)
}

Q5: 如何处理非常大的项数?

A: 对于超过 50 项,需要使用 BigInteger:

import java.math.BigInteger

fun fibonacciBig(n: Int): List<BigInteger> {
    val fib = mutableListOf<BigInteger>()
    if (n >= 1) fib.add(BigInteger.ZERO)
    if (n >= 2) fib.add(BigInteger.ONE)
    
    for (i in 2 until n) {
        fib.add(fib[i - 1] + fib[i - 2])
    }
    return fib
}

总结

关键要点

  • ✅ 使用 Long 处理大数字
  • ✅ 使用迭代而不是递归
  • ✅ 检查边界条件和特殊情况
  • ✅ 利用斐波那契数列的数学性质
  • ✅ KMP 能无缝编译到 JavaScript

下一步

  1. 实现其他数列 (卢卡斯、比布那奇等)
  2. 添加更多数学分析
  3. 实现斐波那契数列的应用
  4. 优化大数字处理
  5. 添加可视化功能

参考资源

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐