You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby字符串类多项式运算代码调试:修复simplify方法报错

Ruby字符串类模拟多项式运算的调试问题

我正在重写Ruby的String类,让它能像代数表达式一样运算——比如"x" + "1"返回"x + 1"而非"x1","x - 1" * "x + 1"返回"x² - 1"而非报错。基础运算方法已完成,但调试自定义的String::simplify方法时遇到问题:执行puts ("x - 1"*"x + 1").simplify时,在String::minus方法第138行触发错误:comparison of nil with 2 failed。可疑方法为String::simplify、String::simplify2和String::minus。

相关代码如下:

class String
  @@powers = %w(⁻ ˙ ⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹)
  @@store = Hash[(["-","."]+[*"0".."9"]).zip @@powers]
  @@reply = "Sorry ,super strings can't tolerate your madness"
  def monomial?;self.terms.size == 1end
  def polynomial?;!self.monomial?end
  def * b #multiplication
    if(self.polynomial? or b.polynomial?)
      s = []
      self.terms.each do |i|
        b.terms.each do |j|
          q = i._ j
          q.end_with?("x¹") ? s << q.chomp("¹") : s << q
        end
      end
      return s.join " + "
    end
    self._ b
  end
  def _ b #multiplication of two terms
    @negative = 1
    @negative *= -1 if self.include? "-"
    @negative *= -1 if b.include? "-"
    self.gsub!("x","x¹") if self.scan(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/).empty?
    b.gsub!("x","x¹") if b.scan(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/).empty? 
    self.gsub!("x","1x") if self.scan(/\d+/).empty?
    b.gsub!("x","1x") if b.scan(/\d+/).empty? 
    m = "#{@negative}".scan(/\D+/).join
    x = "#{self.scan(/\d+/).join.to_i * b.scan(/\d+/).join.to_i}x#{(self.scan(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/).join.unsup.to_i + b.scan(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/).join.unsup.to_i).to_s.sup}".gsub(/(\D*)(1x)/,"\1x")
    if x.scan(/\d+/).empty?
      x.gsub! "x⁰","1"
    else
      x.gsub! "x⁰",""
    end
    return "0" if (m+x) == "-0"
    return m+x
  end
  def sup;self.gsub /\S/,@@store;end #from normal to supersrcipt string
  def unsup #from superscript to normal string
    self.gsub /[⁻⁰¹²³⁴⁵⁶⁷⁸⁹]/,@@store.invert
  end
  def ** n;([self]*n).reduce :*end #exponentiation of expression 
  def degree #degree of polynomial 
    z = self.dup
    z.gsub!("x","x¹") if z.scan(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/).empty?
    z.terms.map{_1.scan(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/).join.unsup.to_i}.max
  end
  
  def a b #addition of two terms
    self.gsub!("x","1x") if self.scan(/\d+/).empty?
    b.gsub!("x","1x") if b.scan(/\d+/).empty?
    if self.degree == b.degree
      x = "#{self.scan(/\d+/).join.to_i + b.scan(/\d+/).join.to_i}x#{b.degree.to_s.sup}"
      if x.scan(/\d+/).empty?
        x.gsub! "x⁰","1"
      else
        x.gsub! "x⁰",""
      end
      x.chomp!("¹") if x.end_with? "x¹"
      return x
    end
    return (a + " + " + b).gsub "+ -","-"
  end
  def terms;self.gsub("-","+ -").split " + "end #to get the terms of an expression in array
  
  def simplify #to simplify the given expression
    return self.simplify2 unless self[1..].include? "-"
    a = self.terms
    p = a.reject{_1[0] == "-"}.join(" + ").gsub("+ -","-")
    n = (a.select{_1[0] == "-"}).map{_1[1..]}.join(" + ").gsub("+ -","-")
    p.minus n
  end
   
  def simplify2 #to simplify the expression containing only positive sign terms
    a = self.terms
    e = a.map &:degree
    ex = self.ex
    h = Hash[ex.zip([[]]*a.size)]
    a.size.times{h[e[_1]] += [_1]}
    s = []
    for i in ex.sort.reverse
      s << h[i].map{a[_1]}.reduce(:a)
    end
    s.join(" + ").gsub "+ -","-"
  end

  def add b #addition of two expressions
    (self + " + " + b).gsub("+ -","-").simplify2
  end
  def describe #describing the type of polynomial
    "Yep,so #{self} is degree #{self.degree} polynomial"
  end
  def coeff #to get the coefficient of a term
    return @@reply if self.polynomial?
    self.gsub! "x","1x" if self.scan(/\d+/).empty?
    self.scan(/-*\d+/).join.to_i
  end
  def coeffs #to get the coefficients of the terms in array
    return @@reply if self.monomial?
    self.terms.map{_1.gsub! "x","1x" if _1.scan(/\d+/).empty?;_1.scan(/-*\d+/).join.to_i}
  end
  
  def m b #to subtract two terms
    if self.degree == b.degree
      c,d = self.coeff - b.coeff,b.degree
      return "0" if c.zero?
      if d.zero?
        return "#{c}x#{b.degree.to_s.sup}".gsub "x⁰",""
      elsif d == 1
        return "#{c}x#{b.degree.to_s.sup}".gsub "x¹","x"
      end
      return "#{c}x#{b.degree.to_s.sup}"
    end
    (self + " - " + b).gsub "- -","+"
  end
  
  def - b
    return @@reply if self.polynomial? or b.polynomial?
    self.m b
  end
  def minus b #subtraction of two expressions
    a,b = self.simplify2,b.simplify2
    s = []
    e1,e2 = a.terms.size,b.terms.size
    e3,e4 = a.terms.map(&:degree),b.terms.map(&:degree)
    m = [a.degree,b.degree].max
    h1 = Hash[[*m.downto(0)].zip([[]]*(m+1))]
    h2 = Hash[[*m.downto(0)].zip([[]]*(m+1))]
    e1.times{h1[e3[_1]] += [_1]}
    e2.times{h2[e4[_1]] += [_1]}
    m.downto(0){
      if h1[_1].empty? && h2[_1].empty?
        #shoot the user
      elsif h1[_1].empty?
        s << "-#{b.terms[h2[_1][0]]}"
      elsif h2[_1].empty?
        s << "#{a.terms[h1[_1][0]]}"
      else
        s << a.terms[h1[_1][0]].m(b.terms[h2[_1][0]])
      end
    }
    s.join(" + ").gsub("+ -","-").gsub(/[+-] 0 /,"").terms.join(" + ").gsub "+ -","- "
  end
  def ex;self.terms.map(&:degree).uniq;end
  
  def negative?;self[0] == "-"end #checking whether the term is negative or not
  
  def positive?;!self.positive?end #checking whether the term is positive or not
end

class Array
  def form #defining this method to convert the array returned by terms to reform the expression
    self.join(" + ").gsub "+ -","-"
  end
end

问题定位与修复方案

1. 修复positive?方法的无限递归

原代码中positive?方法定义为def positive?;!self.positive?end,会导致无限递归调用,引发栈溢出并间接产生nil值。
修复后:

def positive?; !self.negative? end

2. 修复simplify2的哈希初始化错误

原代码中h = Hash[ex.zip([[]]*a.size)]会让所有键指向同一个数组实例,导致分组逻辑完全错误。
修复后:

def simplify2
  a = self.terms
  e = a.map &:degree
  h = Hash.new { |hash, key| hash[key] = [] }
  a.each_with_index do |term, idx|
    h[e[idx]] << term
  end
  s = []
  h.keys.sort.reverse.each do |deg|
    s << h[deg].reduce(:a)
  end
  s.join(" + ").gsub "+ -","-"
end

3. 修复degree方法的常数项处理

原方法无法正确识别常数项的次数(应为0),会导致nil值出现。
修复后:

def degree
  z = self.dup
  if z.include?("x")
    z.gsub!("x","x¹") if z.scan(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/).empty?
    z.terms.map { |term| term.include?("x") ? term.scan(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/).join.unsup.to_i : 0 }.max
  else
    0
  end
end

4. 修复minus方法的空数组索引访问

原方法中直接访问空数组的索引0会返回nil,引发数值比较错误。
修复后片段:

m.downto(0) do |deg|
  if h1[deg].empty? && h2[deg].empty?
    next
  elsif h1[deg].empty?
    s << "-#{b.terms[h2[deg][0]]}" unless h2[deg].empty?
  elsif h2[deg].empty?
    s << "#{a.terms[h1[deg][0]]}" unless h1[deg].empty?
  else
    s << a.terms[h1[deg][0]].m(b.terms[h2[deg][0]])
  end
end

内容的提问来源于stack exchange,提问作者Ash_Blanc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 06:54:55