1

s の配列が与えられた場合、int量子化された値の合計が 100 になるように各値を量子化したいと考えています。各量子化された値も整数である必要があります。これは、配列全体が量子化されている場合に機能しますが、量子化された値のサブセットが加算されると、残りの値に関して量子化されたままになりません。

たとえば、値 44、40、7、2、0、0 は、47、43、8、2、0、0 (合計が 100) に量子化されます。最後の 4 つの量子化された値を取得すると、合計は 53 になり、最初の値と一致します (つまり、47 + 53 = 100)。

しかし、値が 78、7、7、1、0、0 の場合、最後の 4 つの量子化値 (8、8、1、0、0) の合計は 17 です。最初の量子化値は 84 で、17 に加算すると100 と等しくありません。明らかに、この理由は丸めによるものです。サブセットの一貫性を保つために丸めを調整する方法はありますか?

Rubyコードは次のとおりです。

class Quantize
  def initialize(array)
    @array = array.map { |a| a.to_i }
  end

  def values
    @array.map { |a| quantize(a) }
  end

  def sub_total(i, j)
    @array[i..j].map { |a| quantize(a) }.reduce(:+)
  end

  private

  def quantize(val)
    (val * 100.0 / total).round(0)
  end

  def total
    @array.reduce(:+)
  end
end

そして(失敗した)テスト:

require 'quantize'

describe Quantize do
  context 'first example' do
    let(:subject) { described_class.new([44, 40, 7, 2, 0, 0]) }

    context '#values' do
      it 'quantizes array to add up to 100' do
        expect(subject.values).to eq([47, 43, 8, 2, 0, 0])
      end
    end

    context '#sub_total' do
      it 'adds a subset of array' do
        expect(subject.sub_total(1, 5)).to eq(53)
      end
    end
  end

  context 'second example' do
    let(:subject) { described_class.new([78, 7, 7, 1, 0, 0]) }

    context '#values' do
      it 'quantizes array to add up to 100' do
        expect(subject.values).to eq([84, 8, 8, 1, 0, 0])
      end
    end

    context '#sub_total' do
      it 'adds a subset of array' do
        expect(subject.sub_total(1, 5)).to eq(16)
      end
    end
  end
end
4

1 に答える 1

1

質問のコメントにあるように、量子化ルーチンは正しく実行されません。2 番目の例は、100 ではなく 101 に加算[78, 7, 7, 1, 0, 0]されるように量子化されます。[84, 8, 8, 1, 0, 0]

正しい結果が得られるアプローチは次のとおりです。

def quantize(array, value)
  quantized = array.map(&:to_i)
  total = array.reduce(:+)
  remainder = value - total

  index = 0

  if remainder > 0
    while remainder > 0 
      quantized[index] += 1
      remainder -= 1
      index = (index + 1) % quantized.length
    end
  else
    while remainder < 0 
      quantized[index] -= 1
      remainder += 1
      index = (index + 1) % quantized.length
    end
  end

  quantized
end

質問に記載されているように、これで問題は解決します。厄介な結果は になり[80, 8, 8, 2, 1, 1]、これは 100 に追加され、説明したサブセット関係を維持します。もちろん、ソリューションのパフォーマンスを向上させることはできますが、機能し、理解するのが非常に簡単であるという利点があります。

于 2015-04-03T01:28:57.917 に答える