3. 数列通项与求和计算器

功能简介:支持等差数列、等比数列的通项公式和前n项和计算,通过可视化展示数列的增长趋势。支持自定义数列类型,计算通项公式、求和公式,以及极限分析,帮助学生理解数列的基本概念和性质。
在这里插入图片描述
ArkTS代码

@Entry
@Component
struct SequenceCalculator {
  @State private sequenceType: string = 'arithmetic'
  @State private a1: number = 1
  @State private d: number = 2
  @State private n: number = 10
  @State private result: string = ''
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  build() {
    Column() {
      Text('🔢 数列通项与求和计算器')
        .fontSize(24).fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })

      Text('数列类型')
        .fontSize(18).fontWeight(FontWeight.Bold)
        .margin({ bottom: 10 })

      Row() {
        Button('等差数列')
          .width(100)
          .onClick(() => {
            this.sequenceType = 'arithmetic'
            this.calculate()
          })
        Button('等比数列')
          .width(100)
          .onClick(() => {
            this.sequenceType = 'geometric'
            this.calculate()
          })
      }

      Text('数列参数')
        .fontSize(18).fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      Row() {
        Text('首项 a₁: ')
          .width(70)
        TextInput({
          placeholder: '首项',
          text: this.a1.toString()
        })
          .width(100)
          .onChange((v: string) => {
            this.a1 = parseFloat(v) || 0
            this.calculate()
          })
      }
      .margin({ bottom: 10 })

      Row() {
        Text(this.sequenceType === 'arithmetic' ? '公差 d: ' : '公比 q: ')
          .width(70)
        TextInput({
          placeholder: this.sequenceType === 'arithmetic' ? '公差' : '公比',
          text: this.d.toString()
        })
          .width(100)
          .onChange((v: string) => {
            this.d = parseFloat(v) || 0
            this.calculate()
          })
      }
      .margin({ bottom: 20 })

      Text('计算设置')
        .fontSize(18).fontWeight(FontWeight.Bold)
        .margin({ bottom: 10 })

      Row() {
        Text('项数 n: ')
          .width(60)
        Slider({ value: this.n, min: 1, max: 20, step: 1 })
          .width(200)
          .onChange((val: number) => {
            this.n = val
            this.calculate()
          })
        Text(this.n.toString())
          .width(40)
      }

      Button('计算')
        .width(100)
        .margin({ top: 20, bottom: 20 })
        .onClick(() => this.calculate())

      Canvas(this.context)
        .width(400).height(300)
        .backgroundColor('#f5f5f5')
        .onReady(() => this.drawSequence())

      Text('计算结果')
        .fontSize(18).fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      Text(this.result)
        .fontSize(16).fontColor('#2196F3')

      Text('数列公式')
        .fontSize(18).fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      Text(this.getSequenceFormulas())
        .fontSize(14).fontColor('#666')

      Text('极限分析')
        .fontSize(18).fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      Text(this.getLimitAnalysis())
        .fontSize(14).fontColor('#666')
    }
    .padding(20)
  }

  private calculate() {
    if (this.sequenceType === 'arithmetic') {
      const an = this.a1 + (this.n - 1) * this.d
      const sn = this.n * (this.a1 + an) / 2
      this.result = `${this.n}项: ${an}, 前${this.n}项和: ${sn}`
    } else {
      const an = this.a1 * Math.pow(this.d, this.n - 1)
      let sn: number
      if (this.d === 1) {
        sn = this.n * this.a1
      } else {
        sn = this.a1 * (1 - Math.pow(this.d, this.n)) / (1 - this.d)
      }
      this.result = `${this.n}项: ${an.toFixed(2)}, 前${this.n}项和: ${sn.toFixed(2)}`
    }
    this.drawSequence()
  }

  private drawSequence() {
    const ctx = this.context
    const width = 400
    const height = 300
    const padding = 50
    
    // 清空画布
    ctx.clearRect(0, 0, width, height)
    
    // 绘制坐标轴
    ctx.beginPath()
    ctx.moveTo(padding, height - padding)
    ctx.lineTo(width - padding, height - padding)
    ctx.moveTo(padding, padding)
    ctx.lineTo(padding, height - padding)
    ctx.strokeStyle = '#000'
    ctx.lineWidth = 1
    ctx.stroke()
    
    // 计算数列值
    const values: number[] = []
    for (let i = 1; i <= this.n; i++) {
      if (this.sequenceType === 'arithmetic') {
        values.push(this.a1 + (i - 1) * this.d)
      } else {
        values.push(this.a1 * Math.pow(this.d, i - 1))
      }
    }
    
    // 计算缩放因子
    const maxValue = Math.max(...values.map(Math.abs)) || 1
    const yScale = (height - 2 * padding) / (2 * maxValue)
    const xScale = (width - 2 * padding) / (this.n - 1 || 1)
    
    // 绘制数列点和连线
    ctx.beginPath()
    ctx.strokeStyle = '#2196F3'
    ctx.lineWidth = 2
    
    for (let i = 0; i < values.length; i++) {
      const x = padding + i * xScale
      const y = height - padding - values[i] * yScale
      
      // 绘制点
      ctx.beginPath()
      ctx.arc(x, y, 5, 0, 2 * Math.PI)
      ctx.fillStyle = '#2196F3'
      ctx.fill()
      ctx.strokeStyle = '#000'
      ctx.stroke()
      
      // 绘制连线
      if (i > 0) {
        const prevX = padding + (i - 1) * xScale
        const prevY = height - padding - values[i - 1] * yScale
        ctx.beginPath()
        ctx.moveTo(prevX, prevY)
        ctx.lineTo(x, y)
        ctx.strokeStyle = '#2196F3'
        ctx.stroke()
      }
      
      // 绘制坐标
      ctx.font = '12px Arial'
      ctx.fillStyle = '#000'
      ctx.fillText((i + 1).toString(), x - 5, height - padding + 15)
      ctx.fillText(values[i].toFixed(1), x - 15, y - 10)
    }
  }

  private getSequenceFormulas(): string {
    if (this.sequenceType === 'arithmetic') {
      return `通项公式: aₙ = a₁ + (n-1)d\n` +
             `前n项和: Sₙ = n(a₁ + aₙ)/2 = na₁ + n(n-1)d/2`
    } else {
      return `通项公式: aₙ = a₁·qⁿ⁻¹\n` +
             `前n项和: Sₙ = a₁(1-qⁿ)/(1-q) (q≠1)\n` +
             `前n项和: Sₙ = na₁ (q=1)`
    }
  }

  private getLimitAnalysis(): string {
    if (this.sequenceType === 'arithmetic') {
      if (this.d === 0) {
        return `极限: lim(n→∞) aₙ = a₁ (常数数列)`
      } else if (this.d > 0) {
        return `极限: lim(n→∞) aₙ = +∞ (递增数列)`
      } else {
        return `极限: lim(n→∞) aₙ = -∞ (递减数列)`
      }
    } else {
      if (Math.abs(this.d) < 1) {
        return `极限: lim(n→∞) aₙ = 0 (收敛数列)`
      } else if (Math.abs(this.d) === 1) {
        if (this.d === 1) {
          return `极限: lim(n→∞) aₙ = a₁ (常数数列)`
        } else {
          return `极限: 不存在 (振荡数列)`
        }
      } else {
        return `极限: lim(n→∞) aₙ = ∞ (发散数列)`
      }
    }
  }
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐