1
votes

Comment incrémenter un grand nombre sous forme de chaîne comme s'il s'agissait d'un entier?

J'ai essayé de trouver des moyens de le faire, je ne peux pas simplement convertir la chaîne en un entier. C'est trop long pour être un int, c'est la raison pour laquelle j'ai besoin de faire ça. Je peux le faire pour des chiffres uniques, mais dès que je veux ajouter, disons 10 ou 20, je ne sais pas comment changer mon code pour permettre cela. Si j'augmente la boucle, cela augmentera la longueur de la chaîne et cela ne la traiterait pas comme un nombre réel. La raison pour laquelle j'inclus deux langues est que j'accepterai le code C # ou F # dans une réponse.

open System

type String with
    member this.Last() =
        this.[this.Length - 1]

let mutable s = "1234567890" // the numbers I will use are a lot bigger than this.

for i in 0 .. 9 do // 9 is max before it increases the length of the string.
    printfn "%s" s

    let last = (s.Last().ToString() |> int) + 1

    s <- s.[0 .. s.Length - 2] + last.ToString()

Console.Read() |> ignore


8 commentaires

Quel est le problème avec BigInteger ?


Les nombres que j'utiliserai auront parfois plus de 16 chiffres, j'ai essayé et c'est trop gros pour un bigint.


OK, c'est incorrect. Vous devriez aller lire sur BigInteger. BTW 16 chiffres est suffisamment petit pour tenir même dans long .


J'ai essayé let n = BigInteger (10000000000) avec System.Numerics et il dit que le nombre est en dehors de la plage autorisée pour les entiers signés 32 bits. Lorsque j'ajoute des annotations de type pour Int64, cela me dit qu'il attend Int64, mais voici int. Qu'est-ce que je rate?


"Le type BigInteger est un type immuable qui représente un entier arbitrairement grand dont la valeur en théorie n'a pas de limites supérieures ou inférieures." - MSDN


Alanay vous manquez le fait que le compilateur essaiera de faire un int à partir de votre 10000000000 avant qu'il ne soit passé à bigint. Je vous suggère de lire docs.microsoft.com/en-us/dotnet/api/... -" si la valeur que vous avez est trop grande pour un type intégré ... "


@CaiusJard Merci, cela a aidé. Je sais comment les utiliser maintenant.


Soit dit en passant, les décimales vont jusqu'à environ 32 chiffres et peuvent être plus faciles à utiliser pour vous docs.microsoft.com/en-us/dotnet/api/...


3 Réponses :


3
votes

Je doute qu'il y ait une situation où l'utilisation de chaînes pour représenter des nombres serait une bonne idée - vous pouvez utiliser BigInteger pour représenter et travailler avec de grands nombres et il prend en charge toutes les opérations numériques, pas seulement l'incrémentation de un.

Cependant, c'est un problème amusant, alors voici une solution F # possible:

let incString (s:string) = 
  let rec loop acc carry i (s:string) =  
    match i, carry with 
    | -1, true -> System.String(Array.ofList ('1'::acc))
    | -1, false -> System.String(Array.ofList acc)
    | _ ->
      match s.[i], carry with 
      | '9', true -> loop ('0'::acc) true (i-1) s 
      | c, false -> loop (c::acc) false (i-1) s
      | c, true -> loop (char ((int c) + 1)::acc) false (i-1) s
  loop [] true (s.Length-1) s

incString "9899"

La fonction boucle interne prend ce qui suit paramètres:

  • acc est un accumulateur, utilisé pour collecter les chiffres du nouveau numéro (en commençant par la fin)
  • carry est un drapeau booléen qui est true si nous voulons ajouter 1 au numéro suivant (c'est initialement true et ensuite c'est aussi true tant que les chiffres sont 9 - car 9 deviendra 0 et nous devons ensuite ajouter au chiffre suivant de la chaîne).

  • i est l'index actuel, en commençant par le dernier

  • s est la chaîne d'entrée représentant le numéro d'origine.


2 commentaires

Merci beaucoup! La raison pour laquelle j'en avais besoin est de récupérer des images de sites Web qui sont tous des nombres et d'incrémenter pour chaque image, pas seulement de la changer au hasard. Habituellement 16 chiffres et plus. C'est donc très utile!


@Alanay Vous devriez vraiment simplement utiliser BigInteger - voir la modification pour savoir comment faire.



1
votes

vous l'inversez en une liste de caractères essayer d'incrémenter le chiffre le plus bas, si cela ne fonctionne pas (c'est un 9), vous définissez le chiffre le plus bas sur '0' et vous recurse la queue

let inc: string -> string =
    let rec incRev: List<char> -> List<char> =             
        function
        | [] -> [ '1' ]
        | '9' :: cs -> '0' :: incRev cs
        | c :: cs -> char (int c + 1) :: cs
    fun s -> 
        s.ToCharArray() 
        |> Array.toList 
        |> List.rev
        |> incRev
        |> List.rev
        |> Array.ofList
        |> System.String


0 commentaires

0
votes

Une autre réponse probablement un peu plus efficace (je préfère la précédente), mais elle n'a pas tout l'inversion en cours. vous vous pliez à partir du dos de la liste des caractères assemblant une réponse et en passant le chiffre de retenue jusqu'à la fin.

let inc2: string -> string =
    let incDigit : (char * (List<char> * char)) -> (List<char> * char) =
        function 
        | (c,(a,'0'))   -> (c :: a,'0')
        | ('9',(a,'1')) -> ('0' :: a,'1')
        | (c,(a,'1'))   -> ((char (int c + 1)) :: a,'0')            
    fun s -> 
        let result = 
            (s.ToCharArray() 
            |> Array.toList 
            |> List.foldBack (fun c state -> incDigit (c,state))) ([],'1')
        result
        |> fst
        |> if (snd result = '1') then (fun cs -> '1' :: cs) else id
        |> Array.ofList
        |> System.String


1 commentaires

oui, je suis d'accord ... pour être honnête, j'essayais juste de trouver une excuse pour utiliser le repli