Paradoja de prorrateo

10

Dado:

  • Un número natural S .
  • Una lista de N pesos ponderales W que suman 1.

Devuelve una lista L de N enteros no negativos, de modo que:

(1) sum(L) = S
(2) sum((S⋅W_i - L_i)^2) is minimal

En otras palabras, aproxima S⋅W_is con números enteros lo más cerca posible.

Ejemplos:

1 [0.4 0.3 0.3] = [1 0 0]
3 [0 1 0] = [0 3 0]
4 [0.3 0.4 0.3] = [1 2 1]
5 [0.3 0.4 0.3] = [2 2 1] or [1 2 2] but not [1 3 1]
21 [0.3 0.2 0.5] = [6 4 11]
5 [0.1 0.2 0.3 0.4] = [1 1 1 2] or [0 1 2 2]
4 [0.11 0.3 0.59] = [1 1 2]
10 [0.47 0.47 0.06] = [5 5 0]
10 [0.43 0.43 0.14] = [4 4 2]
11 [0.43 0.43 0.14] = [5 5 1]

Reglas:

  • Puede usar cualquier formato de entrada, o simplemente proporcionar una función que acepte la entrada como argumentos.

Antecedentes:

Este problema surge cuando se muestran S de diferentes tipos de elementos en diferentes proporciones W i con respecto a los tipos.

Otro ejemplo de este problema es la representación política proporcional, ver la paradoja de la distribución . Los dos últimos casos de prueba se conocen como la paradoja de Alabama.

Como estadístico, reconocí este problema como equivalente a un problema encontrado en la identificación de tamaños de muestra al realizar una muestra estratificada. En esa situación, queremos hacer que la proporción de cada estrato en la muestra sea igual a la proporción de cada estrato en la población. - @tomi

glebm
fuente
¿Podría decir con palabras cuál es la tarea? Tengo problemas para descomprimir las expresiones en algo intuitivo.
xnor
Ambos deben ser ≤, fijos. La tarea es presentar un número entero como una suma de números enteros basados ​​en pesos. El resto debe distribuirse favoreciendo los pesos más altos, aunque no estoy seguro de que este requisito esté codificado correctamente. Esto es interesante porque round(A + B) != round(A) + round(B)una solución corta requiere una idea de lo que está sucediendo aquí.
glebm
1
Tal vez cambie las reglas para minimizar la suma de las distancias al L[i] - S*W[i]cuadrado, en lugar de la regla 2 y la regla 3. Esto sería aproximado S*W[i].
Jakube
1
También [0 1 2 2] es otra posible solución para5 [0.1 0.2 0.3 0.4]
Jakube
1
Tal vez debería agregar un ejemplo para 1 [0.4 0.3 0.3]
aditsu se retiró porque SE es MAL

Respuestas:

6

APL, 21

{{⍵+1=⍋⍋⍵-⍺}⍣⍺/⍺0×⊂⍵}

Esta es una traducción de la respuesta CJam de 37 bytes de aditsu .

Pruébelo en línea .

Explicación

 {      ⍵-⍺}            ⍝ Right argument - left argument.
 {  1=⍋⍋⍵-⍺}            ⍝ Make one of the smallest number 1, others 0.
 {⍵+1=⍋⍋⍵-⍺}            ⍝ Add the result and the right argument together.
 {⍵+1=⍋⍋⍵-⍺}⍣⍺          ⍝ Repeat that S times. The result of each iteration is the new right argument.
                  ⊂⍵    ⍝ Return enclosed W, which is taken as one unit in APL.
               ⍺0×⊂⍵    ⍝ Return S*W and 0*W.
{{⍵+1=⍋⍋⍵-⍺}⍣⍺/⍺0×⊂⍵}   ⍝ Make S*W the left argument, 0*W the right argument in the first iteration.
jimmy23013
fuente
7

Pitón 2, 95 83 132 125 143

Mi primer (y segundo) (y tercer) algoritmo tuvo problemas, así que después de una (¡otra!) Reescritura y más pruebas, aquí está (realmente espero) una solución correcta y rápida:

def a(b,h):
 g=h;c=[];d=[]
 for w in b:f=int(w*h);d+=[f];c+=[h*w-f];g-=f
 if g:
  for e in sorted(c)[-g:]:i=c.index(e);c[i]=2;d[i]+=1
 return d

La fuente antes del minificador ahora se ve así:

# minified 143 bytes
def golfalloc(weights, num):
    # Tiny seq alloc for golfing
    gap = num;
    errors = [];
    counts = []
    for w in weights :
        count = int(w*num);
        counts += [count];
        errors += [num*w - count];
        gap -= count
    if gap:
        for e in sorted(errors)[-gap:] :
            i = errors.index(e);
            errors[i] = 2;
            counts[i] += 1
    return counts

Las pruebas regresan:

Pass                    Shape    N               Result Error                        AbsErrSum
ok            [0.4, 0.3, 0.3]    1            [1, 0, 0] -0.60,+0.30,+0.30                 1.20
ok                  [0, 1, 0]    3            [0, 3, 0] +0.00,+0.00,+0.00                 0.00
ok            [0.3, 0.4, 0.3]    4            [1, 2, 1] +0.20,-0.40,+0.20                 0.80
ok            [0.3, 0.4, 0.3]    5            [2, 2, 1] -0.50,+0.00,+0.50                 1.00
ok            [0.3, 0.2, 0.5]   21           [6, 4, 11] +0.30,+0.20,-0.50                 1.00
ok       [0.1, 0.2, 0.3, 0.4]    5         [1, 1, 1, 2] -0.50,+0.00,+0.50,+0.00           1.00
ok          [0.11, 0.3, 0.59]    4            [1, 1, 2] -0.56,+0.20,+0.36                 1.12
ok         [0.47, 0.47, 0.06]   10            [5, 5, 0] -0.30,-0.30,+0.60                 1.20
ok         [0.43, 0.43, 0.14]   10            [4, 4, 2] +0.30,+0.30,-0.60                 1.20
ok         [0.43, 0.43, 0.14]   11            [5, 5, 1] -0.27,-0.27,+0.54                 1.08

Este algoritmo es similar a otras respuestas aquí. Es O (1) para num, por lo que tiene el mismo tiempo de ejecución para los enteros 10 y 1000000. Teóricamente es O (nlogn) para el número de pesos (debido al tipo). Si esto resiste todos los demás casos de entrada difíciles, reemplazará el algoritmo a continuación en mi caja de herramientas de programación.

Por favor, no use ese algoritmo con nada que no sea de golf. Hice compromisos en la velocidad para minimizar el tamaño de la fuente. El siguiente código usa la misma lógica pero es mucho más rápido y más útil:

def seqalloc(anyweights, num):
    # Distribute integer num depending on weights.
    # weights may be non-negative integers, longs, or floats.
    totalbias = float(sum(anyweights))
    weights = [bias/totalbias for bias in anyweights]
    counts = [int(w*num) for w in weights]
    gap = num - sum(counts)
    if gap:
        errors = [num*w - q for w,q in zip(weights, counts)]
        ordered = sorted(range(len(errors)), key=errors.__getitem__)
        for i in ordered[-gap:]:
            counts[i] += 1
    return counts

El valor de num no afecta significativamente la velocidad. Lo he probado con valores del 1 al 10 ^ 19. El tiempo de ejecución varía linealmente con el número de pesos. En mi computadora, tarda 0,15 segundos con 10 ^ 5 pesos y 15 segundos con 10 ^ 7 pesos. Tenga en cuenta que los pesos no están restringidos a fracciones que suman uno. La técnica de clasificación utilizada aquí también es aproximadamente dos veces más rápida que el sorted((v,i) for i,v in enumerate...)estilo tradicional .

Algoritmo Original

Esta fue una función en mi caja de herramientas, modificada un poco para el golf. Originalmente fue de una respuesta SO . Y está mal.

def seqalloc(seq, num):
    outseq = []
    totalw = float(sum(seq))
    for weight in seq:
        share = int(round(num * weight / totalw)) if weight else 0
        outseq.append(share)
        totalw -= weight
        num -= share
    return outseq

Da una aproximación, pero no siempre es correcta, aunque se mantiene la suma (outseq) == num. Rápido pero no recomendado.

Gracias a @alephalpha y @ user23013 por detectar los errores.

EDITAR: Establezca totalw (d) en 1, ya que OP especifica que la suma de los pesos siempre será 1. Ahora 83 bytes.

EDIT2: Se corrigió el error encontrado para [0.4, 0.3, 0.3], 1.

EDIT3: Algoritmo defectuoso abandonado. Se agregó uno mejor.

EDIT4: Esto se está volviendo ridículo. Reemplazado con el algoritmo correcto (realmente espero).

EDITAR5: Se agregó código que no es de golf para otros que quieran usar este algoritmo.

Caballero Lógico
fuente
44
a([0.4, 0.3, 0.3], 1)vuelve [0, 1, 0], mientras que la respuesta correcta es [1, 0, 0].
alephalpha
1
Sigue siendo incorrecto. a([0.11,0.3,0.59],4)devuelto [0, 1, 3]. Debe ser [1, 1, 2].
jimmy23013
1
f([0.47,0.47,0.06],10)devuelto [5, 4, 1]. Debe ser [5, 5, 0].
jimmy23013
2
Creo que es correcto ahora.
jimmy23013
2
@CarpetPython Pasé por un proceso similar con este algoritmo, y así es como se me ocurrió este problema. Si le quitan su licencia, también deberían quitar la mía :)
glebm
4

Mathematica, 67 50 46 45 caracteres

f=(b=⌊1##⌋;b[[#~Ordering~-Tr@#&[b-##]]]++;b)&

Sin golf:

f[s_, w_] := Module[{a = s*w, b, c, d},
  b = Floor[a];
  c = b - a;
  d = Ordering[c, -Total[c]];
  b[[d]] += 1;
  b]

Ejemplo:

f[5,{0.1,0.2,0.3,0.4}]

{1, 1, 1, 2}

alephalpha
fuente
¡Dios mío, eso es corto, teniendo en cuenta que es Mathematica!
DavidC
3

CJam - 37

q~:W,0a*\:S{[_SWf*]z::-_:e<#_2$=)t}*p

Pruébalo en línea

Explicación:

q~             read and evaluate the input
               (pushing the number and the array on the stack)
:W,            save the array in variable W and calculate its length (N)
0a*            make an array of N zeros (the initial "L")
\:S            swap it with the number and save the number in S
{…}*           execute the block S times
    [_SWf*]    make a matrix with 2 rows: "L" and S*W
    z          transpose the matrix, obtaining rows of [L_i S*W_i]
    ::-_       convert to array of L_i-S*W_i and duplicate
    :e<        get the smallest element
    #          find its index in the unsorted array,
               i.e. the "i" with the largest S*W_i-L_i
    _2$=)t     increment L_i
p              print the result nicely

Notas:

  • La complejidad es acerca de O (S * N), por lo que se vuelve muy lenta para S grande
  • CJam carece de operadores aritméticos para 2 matrices, algo que planeo implementar más tarde

Idea diferente - 46

q~:Sf*_:m[_:+S\-@[1f%_,,]z{0=W*}$<{1=_2$=)t}/p

Pruébalo en línea

Esto es mucho más sencillo y eficiente, pero, por desgracia, es un poco más largo. La idea aquí es comenzar con L_i = floor (S * W_i), determinar la diferencia (digamos D) entre S y su suma, encontrar los índices D con la mayor parte fraccional de S * W_i (ordenando y tomando D superior) e incremente L_i para esos índices. Complejidad O (N * log (N)).

aditsu renunció porque SE es MALO
fuente
Ahora está el O (N) :e<.
jimmy23013
@ user23013 oh sí, para el primer programa, gracias
aditsu se retiró porque SE es MALO
¡Eso fue rápido! Felicidades 🌟
glebm
Para aquellos que se preguntan, reemplazar el ordenamiento por un algoritmo de selección de tiempo lineal produciría O (n) en lugar del O (nlogn) real causado por el ordenamiento: Encuentre el D-ésimo elemento más grande, P, en O (N), luego incremente elementos que son ≥PD veces (O (N) desde D <= N).
glebm
@glebm eso es genial, pero creo que hay un problema si varios elementos tienen el mismo valor (P). Tal vez pueda resolverlo en 2 pasadas: primero incremente y cuente los elementos> P, luego sepa cuántos elementos = P se necesitan. O si puede obtener esa información del algoritmo de selección, aún mejor.
Aditsu renunció porque SE es MAL
3

JavaScript (ES6) 126 130 104 115 156 162 194

Después de todos los comentarios y casos de prueba en la respuesta de @ CarpetPython, volviendo a mi primer algoritmo. Por desgracia, la solución inteligente no funciona. La implementación se acortó un poco, aún intenta todas las soluciones posibles, calcula la distancia al cuadrado y mantiene el mínimo.

Editar Para cada elemento de salida de peso w, 'todos' los valores posibles son solo 2: trunc (w * s) y trunc (w * s) +1, por lo que solo hay (2 ** elementos) posibles soluciones para probar.

Q=(s,w)=>
  (n=>{
    for(i=0;
        r=q=s,(y=i++)<1<<w.length;
        q|r>n||(n=r,o=t))
      t=w.map(w=>(f=w*s,q-=d=0|f+(y&1),y/=2,f-=d,r+=f*f,d));
  })()||o

Prueba en la consola Firefox / FireBug

;[[ 1,  [0.4, 0.3, 0.3]      ]
, [ 3,  [0, 1, 0]            ]
, [ 4,  [0.3, 0.4, 0.3]      ]
, [ 5,  [0.3, 0.4, 0.3]      ]
, [ 21, [0.3, 0.2, 0.5]      ]
, [ 5,  [0.1, 0.2, 0.3, 0.4] ]
, [ 4,  [0.11, 0.3, 0.59]    ]
, [ 10, [0.47, 0.47, 0.06]   ]
, [ 10, [0.43, 0.43, 0.14]   ]
, [ 11, [0.43, 0.43, 0.14]   ]]
.forEach(v=>console.log(v[0],v[1],Q(v[0],v[1])))

Salida

1 [0.4, 0.3, 0.3] [1, 0, 0]
3 [0, 1, 0] [0, 3, 0]
4 [0.3, 0.4, 0.3] [1, 2, 1]
5 [0.3, 0.4, 0.3] [1, 2, 2]
21 [0.3, 0.2, 0.5] [6, 4, 11]
5 [0.1, 0.2, 0.3, 0.4] [0, 1, 2, 2]
4 [0.11, 0.3, 0.59] [1, 1, 2]
10 [0.47, 0.47, 0.06] [5, 5, 0]
10 [0.43, 0.43, 0.14] [4, 4, 2]
11 [0.43, 0.43, 0.14] [5, 5, 1]

Esa es una solución más inteligente. Paso único en matriz de pesos.
Para cada pase, encuentro el valor máximo actual en w. Cambio este valor en su lugar con el valor entero ponderado (redondeado hacia arriba), por lo que si s == 21 yw = 0.4, obtenemos 0.5 * 21 -> 10.5 -> 11. Almaceno este valor negado, por lo que no puede se encuentra como máximo en el siguiente ciclo. Luego reduzco la suma total en consecuencia (s = s-11) y también reduzco el total de los pesos en la variable f.
El ciclo finaliza cuando no se encuentra un máximo por encima de 0 (todos los valores! = 0 se han gestionado).
Por fin devuelvo los valores cambiados a positivo nuevamente. Advertencia: este código modifica la matriz de pesos en su lugar, por lo que debe llamarse con una copia de la matriz original

F=(s,w)=>
 (f=>{
  for(;j=w.indexOf(z=Math.max(...w)),z>0;f-=z)
    s+=w[j]=-Math.ceil(z*s/f);
 })(1)||w.map(x=>0-x)

Mi primer intento

No es una solución tan inteligente. Para cada resultado posible, evalúa la diferencia y mantiene el mínimo.

F=(s,w,t=w.map(_=>0),n=NaN)=>
  (p=>{
    for(;p<w.length;)
      ++t[p]>s?t[p++]=0
      :t.map(b=>r+=b,r=p=0)&&r-s||
        t.map((b,i)=>r+=(z=s*w[i]-b)*z)&&r>n||(n=r,o=[...t])
  })(0)||o

Desengañado y explicado

F=(s, w) =>
{
  var t=w.map(_ => 0), // 0 filled array, same size as w
      n=NaN, // initial minumum NaN, as "NaN > value"  is false for any value
      p, r
  // For loop enumerating from [1,0,0,...0] to [s,s,s...s]
  for(p=0; p<w.length;)
  {
    ++t[p]; // increment current cell
    if (t[p] > s)
    {
      // overflow, restart at 0 and point to next cell
      t[p] = 0;
      ++p;
    }
    else
    {
      // increment ok, current cell is the firts one
      p = 0;
      r = 0;
      t.map(b => r += b) // evaluate the cells sum (must be s)
      if (r==s)
      {
        // if sum of cells is s
        // evaluate the total squared distance (always offset by s, that does not matter)
        t.map((b,i) => r += (z=s*w[i]-b)*z) 
        if (!(r > n))
        {
          // if less than current mininum, keep this result
          n=r
          o=[...t] // copy of t goes in o
        }
      }
    }
  }
  return o
}
edc65
fuente
2

CJam, 48 bytes

Una solución directa al problema.

q~:Sf*:L,S),a*{m*{(+}%}*{1bS=},{L]z::-Yf#:+}$0=p

La entrada va como

[0.3 0.4 0.3] 4

Explicación:

q~:S                                 "Read and parse the input, store sum in S";
    f*:L                             "Do S.W, store the dot product in L";
         S),                         "Get array of 0 to S";
        ,   a*                       "Create an array with N copies of the above array";
              {m*{(+}%}*             "Get all possible N length combinations of 0 to S ints";
                        {1bS=},      "Filter to get only those which sum up to S";
{L]z::-Yf#:+}$                       "Sort them based on (S.W_i - L_i)^2 value";
 L                                   "Put the dot product after the sum combination";
  ]z                                 "Wrap in an array and transpose";
    ::-                              "For each row, get difference, i.e. S.W_i - L_i";
       Yf#                           "Square every element";
          :+                         "Take sum";
              0=p                    "After sorting on sum((S.W_i - L_i)^2), take the";
                                     "first element, i.e. smallest sum and print it";

Pruébalo en línea aquí

Optimizador
fuente
2

Pyth: 40 bytes

Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUH

Esto define una función gcon 2 parámetros. Puedes llamarlo así Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUHg5 [0.1 0.2 0.3 0.4.

Pruébelo en línea: Pyth Compiler / Executor

Explicación:

mms+*G@Hb}bklHyUH     (G is S, H is the list of weights)
m             yUH    map each subset k of [0, 1, ..., len(H)-1] to:
 m          lH          map each element b of [0, 1, ..., len(H)-1] to: 
    *G@Hb                  G*H[b]
   +     }bk               + b in k
  s                       floor(_)

Esto crea todas las soluciones posibles L, donde L[i] = floor(S*W[i])o L[i] = floor(S*W[i]+1). Por ejemplo, la entrada 4 [0.3 0.4 0.3crea [[1, 1, 1], [2, 1, 1], [1, 2, 1], [1, 1, 2], [2, 2, 1], [2, 1, 2], [1, 2, 2], [2, 2, 2]].

fqsTG...  
f    ... only use the solutions, where
 qsTG       sum(solution) == G

Solo [[2, 1, 1], [1, 2, 1], [1, 1, 2]]queda.

Mhosm^-*Ghded2C,HN
  o                  order the solutions by
   s                   the sum of 
    m         C,HN       map each element d of zip(H, solution) to
     ^-*Ghded2           (G*d[0] - d[1])^2
 h                   use the first element (minimum)
M                    define a function g(G,H): return _
Jakube
fuente
2

Mathematica 108

s_~f~w_:=Sort[{Tr[(s*w-#)^2],#}&/@ 
Flatten[Permutations/@IntegerPartitions[s,{Length@w},0~Range~s],1]][[1,2]]

f[3, {0, 1, 0}]
f[4, {0.3, 0.4, 0.3}]
f[5, {0.3, 0.4, 0.3}]
f[21, {0.3, 0.2, 0.5}]
f[5, {0.1, 0.2, 0.3, 0.4}]

{0, 3, 0}
{1, 2, 1}
{1, 2, 2}
{6, 4, 11}
{0, 1, 2, 2}


Explicación

Sin golf

f[s_,w_]:=
Module[{partitions},
partitions=Flatten[Permutations/@IntegerPartitions[s,{Length[w]},Range[0,s]],1];
Sort[{Tr[(s *w-#)^2],#}&/@partitions][[1,2]]]

IntegerPartitions[s,{Length@w},0~Range~s]devuelve todos los tabiques enteros de s, utilizando elementos tomados del conjunto {0, 1, 2, ...s}con la restricción de que la salida debe contener el mismo número de elementos que en el conjunto de pesos, w.

Permutations da todos los arreglos ordenados de cada partición entera.

{Tr[(s *w-#)^2],#}devuelve una lista de pares ordenados, {error, permutation} para cada permutación.

Sort[...] ordena la lista de {{error1, permutation1},{error2, permutation2}...according to the size of the error.

[[1,2]]]o Part[<list>,{1,2}]devuelve el segundo elemento del primer elemento en la lista ordenada de {{error, permutation}...}. En otras palabras, devuelve la permutación con el error más pequeño.

DavidC
fuente
2

R, 85 80 76

Utiliza el método de cuota de liebre.

Se eliminó un par después de ver la especificación de que W sumará a 1

function(a,b){s=floor(d<-b*a);s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s}

Prueba de funcionamiento

> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(3,c(0,1,0))
[1] 0 3 0
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(1,c(0.4,0.3,0.3))
[1] 1 0 0
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(4,c(0.3, 0.4, 0.3))
[1] 1 2 1
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(5,c(0.3, 0.4, 0.3))
[1] 1 2 2
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(21,c(0.3, 0.2, 0.5))
[1]  6  4 11
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(5,c(0.1,0.2,0.3,0.4))
[1] 1 1 1 2
>
MickyT
fuente
2

Python, 139 128 117 bytes

def f(S,W):
 L=(S+1,0,[]),
 for n in W:L=[(x-i,y+(S*n-i)**2,z+[i])for x,y,z in L for i in range(x)]
 return min(L)[2]

Solución itertools anterior, 139 bytes

from itertools import*
f=lambda S,W:min((sum(x)!=S,sum((S*a-b)**2for a,b in zip(W,x)),list(x))for x in product(*tee(range(S+1),len(W))))[2]
Sp3000
fuente
Me preguntaba si una solución itertools sería posible. Buen trabajo +1. ¿Estoy en lo cierto al pensar que esto tiene O (n ^ 4) complejidad de tiempo?
Logic Knight
La solución de Itertools fue en O(S^len(W))realidad: P. La nueva solución es mucho más rápida, pero aún lenta
Sp3000
2

Octava, 87 76

Golfizado:

function r=w(s,w)r=0*w;for(i=1:s)[m,x]=max(s*w-r);r(x)+=1;endfor endfunction

Sin golf:

function r=w(s,w)
  r=0*w;   # will be the output
  for(i=1:s)
    [m,x]=max(s*w-r);
    r(x)+=1;
  endfor
endfunction

(¡Maldito "endfor" y "endfunction"! Nunca ganaré pero disfruto jugando al golf con un lenguaje "real").

dcsohl
fuente
Buen algoritmo Se puede reemplazar zeros(size(w))con 0*w.
alephalpha
¡Agradable! ¿Por qué no pensé en eso?
dcsohl
1

T-SQL, 167 265

Porque me gusta probar y hacer estos desafíos también en una consulta.

Lo convirtió en una función en línea para ajustarse mejor a la especificación y creó un tipo para los datos de la tabla. Costó un poco, pero esto nunca iba a ser un contendiente. Cada declaración debe ejecutarse por separado.

CREATE TYPE T AS TABLE(A INT IDENTITY, W NUMERIC(9,8))
CREATE FUNCTION W(@ int,@T T READONLY)RETURNS TABLE RETURN SELECT CASE WHEN i<=@-SUM(g)OVER(ORDER BY(SELECT\))THEN g+1 ELSE g END R,A FROM(SELECT A,ROW_NUMBER()OVER(ORDER BY (W*@)%1 DESC)i,FLOOR(W*@)g FROM @T)a

En uso

DECLARE @ INT = 21
DECLARE @T T
INSERT INTO @T(W)VALUES(0.3),(0.2),(0.5)
SELECT R FROM dbo.W(@,@T) ORDER BY A

R
---------------------------------------
6
4
11
MickyT
fuente